merge m-c to fx-team

This commit is contained in:
Rob Campbell 2011-09-21 08:28:43 -03:00
commit ccc89189bc
136 changed files with 72785 additions and 1726 deletions

View File

@ -223,11 +223,15 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
// Function: getStorageData
// Get data to be used for persistent storage of this object.
getStorageData: function TabItem_getStorageData() {
return {
let data = {
url: this.tab.linkedBrowser.currentURI.spec,
groupID: (this.parent ? this.parent.id : 0),
title: this.tab.label
};
if (this.parent.getActiveTab() == this)
data.active = true;
return data;
},
// ----------
@ -339,14 +343,13 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
Utils.assertThrow(!this._reconnected, "shouldn't already be reconnected");
Utils.assertThrow(this.tab, "should have a xul:tab");
let self = this;
let tabData = Storage.getTabData(this.tab);
if (tabData && TabItems.storageSanity(tabData)) {
this.loadThumbnail(tabData);
if (self.parent)
self.parent.remove(self, {immediately: true});
if (this.parent)
this.parent.remove(this, {immediately: true});
let groupItem;
@ -357,22 +360,26 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
}
if (groupItem) {
groupItem.add(self, {immediately: true});
groupItem.add(this, {immediately: true});
// restore the active tab for each group between browser sessions
if (tabData.active)
groupItem.setActiveTab(this);
// if it matches the selected tab or no active tab and the browser
// tab is hidden, the active group item would be set.
if (self.tab == gBrowser.selectedTab ||
(!GroupItems.getActiveGroupItem() && !self.tab.hidden))
UI.setActive(self.parent);
if (this.tab == gBrowser.selectedTab ||
(!GroupItems.getActiveGroupItem() && !this.tab.hidden))
UI.setActive(this.parent);
}
} else {
// create tab group by double click is handled in UI_init().
GroupItems.newTab(self, {immediately: true});
GroupItems.newTab(this, {immediately: true});
}
self._reconnected = true;
self.save();
self._sendToSubscribers("reconnected");
this._reconnected = true;
this.save();
this._sendToSubscribers("reconnected");
},
// ----------

View File

@ -58,6 +58,7 @@ _BROWSER_FILES = \
browser_tabview_bug589324.js \
browser_tabview_bug590606.js \
browser_tabview_bug591706.js \
browser_tabview_bug593283.js \
browser_tabview_bug594958.js \
browser_tabview_bug595020.js \
browser_tabview_bug595191.js \

View File

@ -0,0 +1,75 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const DUMMY_PAGE_URL = "http://example.com/";
let state = {
windows: [{
tabs: [{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: false,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null,"active":true}'
}
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: false,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":1,"title":null}'
}
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: true,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null}'
},
},{
entries: [{ url: DUMMY_PAGE_URL }],
hidden: true,
attributes: {},
extData: {
"tabview-tab": '{"url":"' + DUMMY_PAGE_URL + '","groupID":2,"title":null,"active":true}'
},
}],
selected:1,
_closedTabs: [],
extData: {
"tabview-groups": '{"nextID":3,"activeGroupId":2,"totalNumber":2}',
"tabview-group":
'{"1":{"bounds":{"left":15,"top":28,"width":546,"height":218},' +
'"userSize":{"x":546,"y":218},"title":"","id":1},' +
'"2":{"bounds":{"left":15,"top":261,"width":546,"height":199},' +
'"userSize":{"x":546,"y":199},"title":"","id":2}}',
"tabview-ui": '{"pageBounds":{"left":0,"top":0,"width":976,"height":663}}'
}, sizemode:"normal"
}]
};
function test() {
waitForExplicitFinish();
newWindowWithState(state, function (win) {
registerCleanupFunction(function () win.close());
showTabView(function() {
let cw = win.TabView.getContentWindow();
let groupItems = cw.GroupItems.groupItems;
let groupOne = groupItems[0];
let groupTwo = groupItems[1];
// check the active tab of each group
is(groupOne.getActiveTab(), groupOne.getChild(0), "The active tab item of group one is the first one");
is(groupTwo.getActiveTab(), groupTwo.getChild(1), "The active tab item of group two is the second one");
is(cw.UI.getActiveTab(), groupOne.getChild(0), "The hightlighted tab item is the first one in group one");
// select a group and the second tab should be hightlighted
cw.UI.setActive(groupTwo);
is(cw.UI.getActiveTab(), groupTwo.getChild(1), "The hightlighted tab item is the second one in group two");
finish();
}, win);
});
}

View File

@ -27,6 +27,10 @@ function openContextMenuFor(element, shiftkey) {
// Context menu should be closed before we open it again.
is(contextMenu.state, "closed", "checking if popup is closed");
if (lastElement)
lastElement.blur();
element.focus();
lastElement = element;
var eventDetails = { type : "contextmenu", button : 2, shiftKey : shiftkey };
synthesizeMouse(element, 2, 2, eventDetails, element.ownerDocument.defaultView);
}
@ -555,7 +559,7 @@ function runTest(testNum) {
var testNum = 1;
var subwindow, chromeWin, contextMenu;
var subwindow, chromeWin, contextMenu, lastElement;
var text, link, mailto, input, img, canvas, video_ok, video_bad, video_bad2,
iframe, textarea, contenteditable, inputspell, pagemenu;
@ -577,6 +581,8 @@ function startTest() {
return;
}
lastElement = null;
text = subwindow.document.getElementById("test-text");
link = subwindow.document.getElementById("test-link");
mailto = subwindow.document.getElementById("test-mailto");

View File

@ -1801,6 +1801,26 @@ public:
*/
static void InitializeTouchEventTable();
/**
* Test whether the given URI always inherits a security context
* from the document it comes from.
*/
static nsresult URIInheritsSecurityContext(nsIURI *aURI, PRBool *aResult);
/**
* Set the given principal as the owner of the given channel, if
* needed. aURI must be the URI of aChannel. aPrincipal may be
* null. If aSetUpForAboutBlank is true, then about:blank will get
* the principal set up on it.
*
* The return value is whether the principal was set up as the owner
* of the channel.
*/
static bool SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
nsIChannel* aChannel,
nsIURI* aURI,
PRBool aSetUpForAboutBlank);
static nsresult Btoa(const nsAString& aBinaryData,
nsAString& aAsciiBase64String);

View File

@ -4674,6 +4674,7 @@ nsContentUtils::URIIsLocalFile(nsIURI *aURI)
PRBool isFile;
nsCOMPtr<nsINetUtil> util = do_QueryInterface(sIOService);
// Important: we do NOT test the entire URI chain here!
return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&isFile)) &&
@ -5721,6 +5722,71 @@ nsContentUtils::IsPatternMatching(nsAString& aValue, nsAString& aPattern,
return res == JS_FALSE || rval != JSVAL_NULL;
}
// static
nsresult
nsContentUtils::URIInheritsSecurityContext(nsIURI *aURI, PRBool *aResult)
{
// Note: about:blank URIs do NOT inherit the security context from the
// current document, which is what this function tests for...
return NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
aResult);
}
// static
bool
nsContentUtils::SetUpChannelOwner(nsIPrincipal* aLoadingPrincipal,
nsIChannel* aChannel,
nsIURI* aURI,
PRBool aSetUpForAboutBlank)
{
//
// Set the owner of the channel, but only for channels that can't
// provide their own security context.
//
// XXX: It seems wrong that the owner is ignored - even if one is
// supplied) unless the URI is javascript or data or about:blank.
// XXX: If this is ever changed, check all callers for what owners
// they're passing in. In particular, see the code and
// comments in nsDocShell::LoadURI where we fall back on
// inheriting the owner if called from chrome. That would be
// very wrong if this code changed anything but channels that
// can't provide their own security context!
//
// (Currently chrome URIs set the owner when they are created!
// So setting a NULL owner would be bad!)
//
PRBool inherit;
// We expect URIInheritsSecurityContext to return success for an
// about:blank URI, so don't call NS_IsAboutBlank() if this call fails.
// This condition needs to match the one in nsDocShell::InternalLoad where
// we're checking for things that will use the owner.
if (NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherit)) &&
(inherit || (aSetUpForAboutBlank && NS_IsAboutBlank(aURI)))) {
aChannel->SetOwner(aLoadingPrincipal);
return true;
}
//
// file: uri special-casing
//
// If this is a file: load opened from another file: then it may need
// to inherit the owner from the referrer so they can script each other.
// If we don't set the owner explicitly then each file: gets an owner
// based on its own codebase later.
//
if (URIIsLocalFile(aURI) && aLoadingPrincipal &&
NS_SUCCEEDED(aLoadingPrincipal->CheckMayLoad(aURI, PR_FALSE)) &&
// One more check here. CheckMayLoad will always return true for the
// system principal, but we do NOT want to inherit in that case.
!IsSystemPrincipal(aLoadingPrincipal)) {
aChannel->SetOwner(aLoadingPrincipal);
return true;
}
return false;
}
PRBool
nsContentUtils::IsFullScreenApiEnabled()
{

View File

@ -1130,23 +1130,6 @@ nsObjectLoadingContent::LoadObject(const nsAString& aURI,
return LoadObject(uri, aNotify, aTypeHint, aForceLoad);
}
static PRBool
IsAboutBlank(nsIURI* aURI)
{
// XXXbz this duplicates an nsDocShell function, sadly
NS_PRECONDITION(aURI, "Must have URI");
// GetSpec can be expensive for some URIs, so check the scheme first.
PRBool isAbout = PR_FALSE;
if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
return PR_FALSE;
}
nsCAutoString str;
aURI->GetSpec(str);
return str.EqualsLiteral("about:blank");
}
void
nsObjectLoadingContent::UpdateFallbackState(nsIContent* aContent,
AutoFallback& fallback,
@ -1460,17 +1443,8 @@ nsObjectLoadingContent::LoadObject(nsIURI* aURI,
}
// Set up the channel's principal and such, like nsDocShell::DoURILoad does
PRBool inheritPrincipal;
rv = NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
&inheritPrincipal);
NS_ENSURE_SUCCESS(rv, rv);
if (inheritPrincipal || IsAboutBlank(aURI) ||
(nsContentUtils::URIIsLocalFile(aURI) &&
NS_SUCCEEDED(thisContent->NodePrincipal()->CheckMayLoad(aURI,
PR_FALSE)))) {
chan->SetOwner(thisContent->NodePrincipal());
}
nsContentUtils::SetUpChannelOwner(thisContent->NodePrincipal(),
chan, aURI, PR_TRUE);
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(chan);
if (scriptChannel) {

View File

@ -105,5 +105,13 @@ def web_socket_transfer_data(request):
test37reason = request.ws_close_reason
elif request.ws_protocol == "test-37c":
request.ws_stream.close_connection(test37code, test37reason)
elif request.ws_protocol == "test-42":
# Echo back 3 messages
msgutil.send_message(request,
msgutil.receive_message(request))
msgutil.send_message(request,
msgutil.receive_message(request))
msgutil.send_message(request,
msgutil.receive_message(request))
while not request.client_terminated:
msgutil.receive_message(request)

View File

@ -62,10 +62,12 @@
* 38. ensure extensions attribute is defined
* 39. a basic wss:// connectivity test
* 40. negative test for wss:// with no cert
* 41. HSTS
* 42. non-char utf-8 sequences
*/
var first_test = 1;
var last_test = 40;
var last_test = 42;
var current_test = first_test;
@ -1067,7 +1069,7 @@ function test38()
{
ok(true, "test 38 open");
ok(ws.extensions != undefined, "extensions attribute defined");
ok(ws.extensions == "deflate-stream", "extensions attribute deflate-stream");
// ok(ws.extensions == "deflate-stream", "extensions attribute deflate-stream");
ws.close();
};
@ -1123,6 +1125,44 @@ function test40()
};
}
function test41()
{
// reserve test41 for HSTS - bug 664284
doTest(42);
}
function test42()
{
// test some utf-8 non-characters. They should be allowed in the
// websockets context. Test via round trip echo.
var ws = CreateTestWS("ws://mochi.test:8888/tests/content/base/test/file_websocket", "test-42");
var data = ["U+FFFE ￾",
"U+FFFF ￿",
"U+10FFFF 􏿿"];
var index = 0;
ws.onopen = function()
{
ws.send(data[0]);
ws.send(data[1]);
ws.send(data[2]);
}
ws.onmessage = function(e)
{
ok(e.data == data[index], "bad received message in test-42! index="+index);
index++;
if (index == 3)
ws.close();
}
ws.onclose = function(e)
{
doTest(43);
}
}
var ranAllTests = false;
function maybeFinished()

View File

@ -68,6 +68,8 @@ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
PRBool forceWriteOnly,
PRBool CORSUsed)
{
NS_PRECONDITION(aPrincipal, "Must have a principal here");
// Callers should ensure that mCanvasElement is non-null before calling this
if (!aCanvasElement) {
NS_WARNING("DoDrawImageSecurityCheck called without canvas element!");
@ -83,9 +85,6 @@ DoDrawImageSecurityCheck(nsHTMLCanvasElement *aCanvasElement,
return;
}
if (aPrincipal == nsnull)
return;
// No need to do a security check if the image used CORS for the load
if (CORSUsed)
return;

View File

@ -68,6 +68,7 @@
#include "prenv.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
using namespace mozilla;
using namespace mozilla::gl;
@ -206,6 +207,7 @@ nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult
nsresult
NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult)
{
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
nsIDOMWebGLRenderingContext* ctx = new WebGLContext();
if (!ctx)
return NS_ERROR_OUT_OF_MEMORY;

View File

@ -3604,9 +3604,7 @@ WebGLContext::DOMElementToImageSurface(nsIDOMElement *imageOrCanvas,
// part 1: check that the DOM element is same-origin, or has otherwise been
// validated for cross-domain use.
// if res.mPrincipal == null, no need for the origin check. See DoDrawImageSecurityCheck.
// this case happens in the mochitest for images served from mochi.test:8888
if (res.mPrincipal && !res.mCORSUsed) {
if (!res.mCORSUsed) {
PRBool subsumes;
nsresult rv = HTMLCanvasElement()->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
if (NS_FAILED(rv) || !subsumes) {

View File

@ -1789,37 +1789,6 @@ nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttribu
}
}
void
nsGenericHTMLFormElement::UpdateEditableFormControlState(PRBool aNotify)
{
// nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
// function, so should be kept in sync with that.
ContentEditableTristate value = GetContentEditableValue();
if (value != eInherit) {
DoSetEditableFlag(!!value, aNotify);
return;
}
nsIContent *parent = GetParent();
if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
DoSetEditableFlag(PR_TRUE, aNotify);
return;
}
if (!IsTextControl(PR_FALSE)) {
DoSetEditableFlag(PR_FALSE, aNotify);
return;
}
// If not contentEditable we still need to check the readonly attribute.
PRBool roState;
GetBoolAttr(nsGkAtoms::readonly, &roState);
DoSetEditableFlag(!roState, aNotify);
}
/* static */ const nsGenericHTMLElement::MappedAttributeEntry
nsGenericHTMLElement::sCommonAttributeMap[] = {
@ -2912,6 +2881,18 @@ nsGenericHTMLFormElement::IntrinsicState() const
state |= NS_EVENT_STATE_DEFAULT;
}
// Make the text controls read-write
if (!state.HasState(NS_EVENT_STATE_MOZ_READWRITE) &&
IsTextControl(PR_FALSE)) {
PRBool roState;
GetBoolAttr(nsGkAtoms::readonly, &roState);
if (!roState) {
state |= NS_EVENT_STATE_MOZ_READWRITE;
state &= ~NS_EVENT_STATE_MOZ_READONLY;
}
}
return state;
}

View File

@ -928,8 +928,6 @@ protected:
virtual nsresult AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
const nsAString* aValue, PRBool aNotify);
void UpdateEditableFormControlState(PRBool aNotify);
/**
* This method will update the form owner, using @form or looking to a parent.
*

View File

@ -50,6 +50,7 @@
#include "nsJSUtils.h"
#include "nsMathUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "nsFrameManager.h"
#include "nsDisplayList.h"
@ -779,6 +780,7 @@ nsresult NS_NewCanvasRenderingContext2DAzure(nsIDOMCanvasRenderingContext2D** aR
nsresult
NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult)
{
Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
if (Preferences::GetBool("gfx.canvas.azure.enabled", PR_FALSE)) {
nsresult rv = NS_NewCanvasRenderingContext2DAzure(aResult);
// If Azure fails, fall back to a classic canvas.

View File

@ -848,7 +848,6 @@ nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
UpdateTypeMismatchValidityState();
}
UpdateEditableState(aNotify);
UpdateState(aNotify);
}

View File

@ -235,11 +235,6 @@ public:
NS_IMETHOD FireAsyncClickHandler();
virtual void UpdateEditableState(PRBool aNotify)
{
return UpdateEditableFormControlState(aNotify);
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLInputElement,
nsGenericHTMLFormElement)

View File

@ -200,11 +200,6 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
virtual void UpdateEditableState(PRBool aNotify)
{
return UpdateEditableFormControlState(aNotify);
}
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLTextAreaElement,
nsGenericHTMLFormElement)
@ -1267,9 +1262,6 @@ nsHTMLTextAreaElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
UpdateTooLongValidityState();
}
if (aName == nsGkAtoms::readonly) {
UpdateEditableState(aNotify);
}
UpdateState(aNotify);
}

View File

@ -1559,6 +1559,9 @@ nsTextEditorState::CreateRootNode()
nsresult
nsTextEditorState::InitializeRootNode()
{
// Make our root node editable
mRootNode->SetFlags(NODE_IS_EDITABLE);
// Set the necessary classes on the text control. We use class values
// instead of a 'style' attribute so that the style comes from a user-agent
// style sheet and is still applied even if author styles are disabled.

View File

@ -8171,7 +8171,8 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// One more twist: Don't inherit the owner for external loads.
if (aLoadType != LOAD_NORMAL_EXTERNAL && !owner &&
(aFlags & INTERNAL_LOAD_FLAGS_INHERIT_OWNER) &&
NS_SUCCEEDED(URIInheritsSecurityContext(aURI, &inherits)) &&
NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
&inherits)) &&
inherits) {
owner = GetInheritedPrincipal(PR_TRUE);
@ -8182,11 +8183,13 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// if this document came from an unsafe channel.
{
PRBool willInherit;
// This condition needs to match the one in DoChannelLoad.
// This condition needs to match the one in
// nsContentUtils::SetUpChannelOwner.
// Except we reverse the rv check to be safe in case
// URIInheritsSecurityContext fails here and succeeds there.
rv = URIInheritsSecurityContext(aURI, &willInherit);
if (NS_FAILED(rv) || willInherit || IsAboutBlank(aURI)) {
// nsContentUtils::URIInheritsSecurityContext fails here and
// succeeds there.
rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
do {
nsCOMPtr<nsIDocShell> itemDocShell =
@ -9001,56 +9004,9 @@ nsDocShell::DoURILoad(nsIURI * aURI,
httpChannel->SetReferrer(aReferrerURI);
}
}
//
// Set the owner of the channel, but only for channels that can't
// provide their own security context.
//
// XXX: Is seems wrong that the owner is ignored - even if one is
// supplied) unless the URI is javascript or data or about:blank.
// XXX: If this is ever changed, check all callers for what owners they're
// passing in. In particular, see the code and comments in LoadURI
// where we fall back on inheriting the owner if called
// from chrome. That would be very wrong if this code changed
// anything but channels that can't provide their own security context!
//
// (Currently chrome URIs set the owner when they are created!
// So setting a NULL owner would be bad!)
//
// If this code ever changes, change nsObjectLoadingContent::LoadObject
// accordingly.
PRBool inherit;
// We expect URIInheritsSecurityContext to return success for an
// about:blank URI, so don't call IsAboutBlank() if this call fails.
// This condition needs to match the one in InternalLoad where
// we're checking for things that will use the owner.
rv = URIInheritsSecurityContext(aURI, &inherit);
if (NS_SUCCEEDED(rv) && (inherit || IsAboutBlank(aURI))) {
channel->SetOwner(aOwner);
}
//
// file: uri special-casing
//
// If this is a file: load opened from another file: then it may need
// to inherit the owner from the referrer so they can script each other.
// If we don't set the owner explicitly then each file: gets an owner
// based on its own codebase later.
//
nsCOMPtr<nsIPrincipal> ownerPrincipal(do_QueryInterface(aOwner));
if (URIIsLocalFile(aURI) && ownerPrincipal &&
NS_SUCCEEDED(ownerPrincipal->CheckMayLoad(aURI, PR_FALSE))) {
// One more check here. CheckMayLoad will always return true for the
// system principal, but we do NOT want to inherit in that case.
PRBool isSystem;
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
if (secMan &&
NS_SUCCEEDED(secMan->IsSystemPrincipal(ownerPrincipal,
&isSystem)) &&
!isSystem) {
channel->SetOwner(aOwner);
}
}
nsContentUtils::SetUpChannelOwner(ownerPrincipal, channel, aURI, PR_TRUE);
nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
if (scriptChannel) {
@ -9452,7 +9408,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
shAvailable, updateHistory, equalUri));
if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
NS_ASSERTION(IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
NS_ASSERTION(NS_IsAboutBlank(mCurrentURI), "no SHEntry for a non-transient viewer?");
}
#endif
@ -9743,7 +9699,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
}
// 2c: Same-origin check.
if (!URIIsLocalFile(newURI)) {
if (!nsContentUtils::URIIsLocalFile(newURI)) {
// In addition to checking that the security manager says that
// the new URI has the same origin as our current URI, we also
// check that the two URIs have the same userpass. (The
@ -11251,47 +11207,6 @@ nsDocShell::GetIsContent(PRBool *aIsContent)
return NS_OK;
}
/* static */
nsresult
nsDocShell::URIInheritsSecurityContext(nsIURI* aURI, PRBool* aResult)
{
// Note: about:blank URIs do NOT inherit the security context from the
// current document, which is what this function tests for...
return NS_URIChainHasFlags(aURI,
nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT,
aResult);
}
/* static */
PRBool
nsDocShell::URIIsLocalFile(nsIURI *aURI)
{
PRBool isFile;
nsCOMPtr<nsINetUtil> util = do_GetNetUtil();
return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI,
nsIProtocolHandler::URI_IS_LOCAL_FILE,
&isFile)) &&
isFile;
}
/* static */
PRBool
nsDocShell::IsAboutBlank(nsIURI* aURI)
{
NS_PRECONDITION(aURI, "Must have URI");
// GetSpec can be expensive for some URIs, so check the scheme first.
PRBool isAbout = PR_FALSE;
if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
return PR_FALSE;
}
nsCAutoString str;
aURI->GetSpec(str);
return str.EqualsLiteral("about:blank");
}
PRBool
nsDocShell::IsOKToLoadURI(nsIURI* aURI)
{

View File

@ -650,15 +650,6 @@ protected:
void DoGetPositionAndSize(PRInt32 * x, PRInt32 * y, PRInt32 * cx,
PRInt32 * cy);
// Check whether aURI should inherit our security context
static nsresult URIInheritsSecurityContext(nsIURI* aURI, PRBool* aResult);
// Check whether aURI is a URI_IS_LOCAL_FILE or not
static PRBool URIIsLocalFile(nsIURI *aURI);
// Check whether aURI is about:blank
static PRBool IsAboutBlank(nsIURI* aURI);
// Call this when a URI load is handed to us (via OnLinkClick or
// InternalLoad). This makes sure that we're not inside unload, or that if
// we are it's still OK to load this URI.

View File

@ -433,22 +433,6 @@ static const char kPkcs11ContractID[] = NS_PKCS11_CONTRACTID;
#endif
static const char sPopStatePrefStr[] = "browser.history.allowPopState";
static PRBool
IsAboutBlank(nsIURI* aURI)
{
NS_PRECONDITION(aURI, "Must have URI");
// GetSpec can be expensive for some URIs, so check the scheme first.
PRBool isAbout = PR_FALSE;
if (NS_FAILED(aURI->SchemeIs("about", &isAbout)) || !isAbout) {
return PR_FALSE;
}
nsCAutoString str;
aURI->GetSpec(str);
return str.EqualsLiteral("about:blank");
}
class nsDummyJavaPluginOwner : public nsIPluginInstanceOwner
{
public:
@ -1615,7 +1599,7 @@ nsGlobalWindow::WouldReuseInnerWindow(nsIDocument *aNewDocument)
return PR_FALSE;
}
NS_ASSERTION(IsAboutBlank(mDoc->GetDocumentURI()),
NS_ASSERTION(NS_IsAboutBlank(mDoc->GetDocumentURI()),
"How'd this happen?");
// Great, we're the original document, check for one of the other
@ -1664,8 +1648,8 @@ nsGlobalWindow::SetOpenerScriptPrincipal(nsIPrincipal* aPrincipal)
// something is really weird.
nsCOMPtr<nsIURI> uri;
mDoc->NodePrincipal()->GetURI(getter_AddRefs(uri));
NS_ASSERTION(uri && IsAboutBlank(uri) &&
IsAboutBlank(mDoc->GetDocumentURI()),
NS_ASSERTION(uri && NS_IsAboutBlank(uri) &&
NS_IsAboutBlank(mDoc->GetDocumentURI()),
"Unexpected original document");
#endif
@ -5013,7 +4997,7 @@ nsGlobalWindow::Focus()
NS_ASSERTION(doc, "Bogus doc?");
nsIURI* ourURI = doc->GetDocumentURI();
if (ourURI) {
lookForPresShell = !IsAboutBlank(ourURI);
lookForPresShell = !NS_IsAboutBlank(ourURI);
}
}

View File

@ -2207,7 +2207,7 @@ class ThreadLocalJSRuntime
JSObject* mGlobal;
static JSClass sGlobalClass;
static const unsigned sRuntimeHeapSize = 64 * 1024; // should be enough for anyone
static const unsigned sRuntimeHeapSize = 256 * 1024; // should be enough for anyone
ThreadLocalJSRuntime()
: mRuntime(NULL), mContext(NULL), mGlobal(NULL)

View File

@ -382,7 +382,7 @@ struct ParamTraits<mozilla::plugins::NPRemoteWindow>
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
uint64_t window;
uint64 window;
int32_t x, y;
uint32_t width, height;
NPRect clipRect;

View File

@ -36,7 +36,9 @@ function init3()
rng.setEnd(textNode, 1);
targetWindow.getSelection().addRange(rng);
targetDocument.execCommand("inserthtml", false, "<p>");
try {
targetDocument.execCommand("inserthtml", false, "<p>");
} catch(e) {}
document.documentElement.removeAttribute("class");
}

View File

@ -548,7 +548,7 @@ public:
virtual PRBool IsContainer(nsIDOMNode *aNode);
/** returns PR_TRUE if aNode is an editable node */
PRBool IsEditable(nsIDOMNode *aNode);
virtual PRBool IsEditable(nsIDOMNode *aNode);
virtual PRBool IsTextInDirtyFrameVisible(nsIDOMNode *aNode);

View File

@ -661,13 +661,8 @@ nsSelectAllCommand::IsCommandEnabled(const char * aCommandName,
{
NS_ENSURE_ARG_POINTER(outCmdEnabled);
// you can select all if there is an editor (and potentially no contents)
// some day we may want to change this
nsCOMPtr<nsIEditor> editor = do_QueryInterface(aCommandRefCon);
if (editor)
return editor->GetIsSelectionEditable(outCmdEnabled);
*outCmdEnabled = PR_FALSE;
// You can always select all!
*outCmdEnabled = PR_TRUE;
return NS_OK;
}

View File

@ -311,7 +311,9 @@ nsHTMLEditor::DoInsertHTMLWithContext(const nsAString & aInputString,
// if caller didn't provide the destination/target node,
// fetch the paste insertion point from our selection
res = GetStartNodeAndOffset(selection, getter_AddRefs(targetNode), &targetOffset);
if (!targetNode) res = NS_ERROR_FAILURE;
if (!targetNode || !IsEditable(targetNode)) {
res = NS_ERROR_FAILURE;
}
NS_ENSURE_SUCCESS(res, res);
}
else

View File

@ -431,6 +431,12 @@ nsHTMLEditor::FindSelectionRoot(nsINode *aNode)
}
if (!content->HasFlag(NODE_IS_EDITABLE)) {
// If the content is in read-write state but is not editable itself,
// return it as the selection root.
if (content->IsElement() &&
content->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) {
return content.forget();
}
return nsnull;
}
@ -6028,3 +6034,22 @@ nsHTMLEditor::GetPreferredIMEState(PRUint32 *aState)
*aState = nsIContent::IME_STATUS_ENABLE;
return NS_OK;
}
PRBool
nsHTMLEditor::IsEditable(nsIDOMNode* aNode) {
if (!nsPlaintextEditor::IsEditable(aNode)) {
return PR_FALSE;
}
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
if (!node) {
// If what we're dealing with is not a node, then it's not editable!
return PR_FALSE;
}
if (node->IsElement()) {
// If we're dealing with an element, then ask it whether it's editable.
return node->IsEditable();
}
// We might be dealing with a text node for example, which we always consider
// to be editable.
return PR_TRUE;
}

View File

@ -154,6 +154,7 @@ public:
virtual already_AddRefed<nsIDOMEventTarget> GetDOMEventTarget();
virtual already_AddRefed<nsIContent> FindSelectionRoot(nsINode *aNode);
virtual PRBool IsAcceptableInputEvent(nsIDOMEvent* aEvent);
virtual PRBool IsEditable(nsIDOMNode *aNode);
/* ------------ nsStubMutationObserver overrides --------- */
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED

View File

@ -73,12 +73,14 @@ _TEST_FILES = \
file_bug549262.html \
test_bug550434.html \
test_bug551704.html \
test_bug552782.html \
test_bug570144.html \
test_bug592592.html \
test_bug597784.html \
test_bug599322.html \
test_bug607584.html \
test_bug611182.html \
test_bug612128.html \
test_bug612447.html \
test_bug620906.html \
test_bug622371.html \

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=552782
-->
<head>
<title>Test for Bug 552782</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=290026">Mozilla Bug 552782</a>
<p id="display"></p>
<div id="editor" contenteditable></div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 552782 **/
SimpleTest.waitForExplicitFinish();
var original = '<ol><li>Item 1</li><ol><li>Item 2</li><li>Item 3</li><li>Item 4</li></ol></ol>';
var editor = document.getElementById("editor");
editor.innerHTML = original;
editor.focus();
addLoadEvent(function() {
var sel = window.getSelection();
sel.removeAllRanges();
var lis = document.getElementsByTagName("li");
sel.selectAllChildren(lis[2]);
document.execCommand("outdent", false, false);
var expected = '<ol><li>Item 1</li><ol><li>Item 2</li></ol><li>Item 3</li><ol><li>Item 4</li></ol></ol>';
is(editor.innerHTML, expected, "outdenting third item in a partially indented numbered list");
document.execCommand("indent", false, false);
todo_is(editor.innerHTML, original, "re-indenting third item in a partially indented numbered list");
// done
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=612128
-->
<head>
<title>Test for Bug 612128</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=612128">Mozilla Bug 612128</a>
<p id="display"></p>
<div id="content">
<input>
<div contenteditable></div>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 612128 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
document.querySelector("input").focus();
var threw = false;
try {
document.execCommand("inserthtml", null, "<span>f" + "oo</span>");
} catch (e) {
threw = true;
}
ok(threw, "The inserthtml command should fail");
is(document.querySelectorAll("span").length, 0, "No span element should be injected inside the page");
is(document.body.innerHTML.indexOf("f" + "oo"), -1, "No text should be injected inside the page");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -35,10 +35,17 @@ var gBlock1, gBlock2;
function IsCommandEnabled(command) {
var enabled;
var resultInNonEditableRegion = false;
if (command == "selectAll") {
// The select all command is sort of exceptional, as it needs to be enabled
// everywhere.
resultInNonEditableRegion = true;
}
// non-editable div: should return false
window.getSelection().selectAllChildren(gBlock1);
enabled = document.queryCommandEnabled(command);
is(enabled, false, "'" + command + "' should not be enabled on a non-editable block.");
is(enabled, resultInNonEditableRegion, "'" + command + "' should not be enabled on a non-editable block.");
// editable div: should return true
window.getSelection().selectAllChildren(gBlock2);

View File

@ -85,6 +85,12 @@ SurfaceDescriptorX11::SurfaceDescriptorX11(gfxXlibSurface* aSurf)
, mFormat(aSurf->XRenderFormat()->id)
{ }
SurfaceDescriptorX11::SurfaceDescriptorX11(const int aXid, const int aXrenderPictID, const gfxIntSize& aSize)
: mId(aXid)
, mSize(aSize)
, mFormat(aXrenderPictID)
{ }
already_AddRefed<gfxXlibSurface>
SurfaceDescriptorX11::OpenForeign() const
{

View File

@ -60,6 +60,8 @@ struct SurfaceDescriptorX11 {
SurfaceDescriptorX11(gfxXlibSurface* aSurf);
SurfaceDescriptorX11(const int aXid, const int aXrenderPictID, const gfxIntSize& aSize);
// Default copy ctor and operator= are OK
bool operator==(const SurfaceDescriptorX11& aOther) const {

View File

@ -12,7 +12,7 @@
#include <sys/int_types.h>
#elif defined (_AIX)
#include <sys/types.h>
#elif !defined(ANDROID)
#elif !defined(ANDROID) && !defined(__OpenBSD__)
typedef PRInt8 int8_t;
typedef PRUint8 uint8_t;
typedef PRInt16 int16_t;

View File

@ -604,7 +604,7 @@ gfxXlibNativeRenderer::Draw(gfxContext* ctx, nsIntSize size,
CopyXlibSurfaceToImage(tempXlibSurface, gfxASurface::ImageFormatRGB24);
if (blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS &&
blackImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
whiteImage->CairoStatus() == CAIRO_STATUS_SUCCESS) {
gfxAlphaRecovery::Analysis analysis;
if (!gfxAlphaRecovery::RecoverAlpha(blackImage, whiteImage,
result ? &analysis : nsnull))

View File

@ -15,6 +15,7 @@
#elif defined(ANDROID)
#include <sys/stat.h>
#elif defined(OS_POSIX)
#include <sys/types.h>
#include <fts.h>
#include <sys/stat.h>
#endif

View File

@ -30,6 +30,11 @@
#include "base/string_util.h"
#include "base/time.h"
// FreeBSD/OpenBSD lacks stat64, but its stat handles files >2GB just fine
#if defined(OS_FREEBSD) || defined(OS_OPENBSD)
#define stat64 stat
#endif
namespace file_util {
#if defined(GOOGLE_CHROME_BUILD)

View File

@ -33,6 +33,9 @@ PlatformThreadId PlatformThread::CurrentId() {
// into the kernel.
#if defined(OS_MACOSX)
return mach_thread_self();
#elif defined (__OpenBSD__)
// TODO(BSD): find a better thread ID
return (intptr_t)(pthread_self());
#elif defined(OS_LINUX)
return syscall(__NR_gettid);
#endif

View File

@ -36,6 +36,8 @@
#include "base/third_party/nspr/prcpucfg_mac.h"
#elif defined(__linux__) || defined(ANDROID)
#include "base/third_party/nspr/prcpucfg_linux.h"
#elif defined(__OpenBSD__)
#include "base/third_party/nspr/prcpucfg_openbsd.h"
#else
#error Provide a prcpucfg.h appropriate for your platform
#endif

View File

@ -0,0 +1,437 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape Portable Runtime (NSPR).
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nspr_cpucfg___
#define nspr_cpucfg___
#ifndef XP_UNIX
#define XP_UNIX
#endif
#ifndef OPENBSD
#define OPENBSD
#endif
#define PR_AF_INET6 24 /* same as AF_INET6 */
#ifndef HAVE_LONG_LONG
#define HAVE_LONG_LONG
#endif
#if defined(__i386__) || defined(__arm__)
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#undef HAVE_ALIGNED_DOUBLES
#undef HAVE_ALIGNED_LONGLONGS
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 4
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 4
#define PR_BYTES_PER_DWORD 8
#define PR_BYTES_PER_WORD_LOG2 2
#define PR_BYTES_PER_DWORD_LOG2 3
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 32
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 32
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 5
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 5
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 4
#define PR_ALIGN_OF_INT64 4
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 4
#define PR_ALIGN_OF_POINTER 4
#elif defined(__amd64__)
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#define IS_64
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 8
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 8
#define PR_BYTES_PER_DWORD 8
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 64
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 64
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 6
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 6
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 8
#define PR_ALIGN_OF_INT64 8
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 8
#define PR_ALIGN_OF_POINTER 8
#define PR_ALIGN_OF_WORD 8
#define PR_BYTES_PER_WORD_LOG2 3
#define PR_BYTES_PER_DWORD_LOG2 3
#define HAVE_ALIGNED_DOUBLES
#define HAVE_ALIGNED_LONGLONGS
#elif defined(__sparc_v9__)
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#define HAVE_ALIGNED_DOUBLES
#define HAVE_ALIGNED_LONGLONGS
#define IS_64
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 8
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 8
#define PR_BYTES_PER_DWORD 8
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 64
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 64
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 6
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 6
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 8
#define PR_ALIGN_OF_INT64 8
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 8
#define PR_ALIGN_OF_POINTER 8
#define PR_BYTES_PER_WORD_LOG2 3
#define PR_BYTES_PER_DWORD_LOG2 3
#elif defined(__sparc__) || defined(__hppa__)
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#define HAVE_ALIGNED_DOUBLES
#define HAVE_ALIGNED_LONGLONGS
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 4
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 4
#define PR_BYTES_PER_DWORD 8
#define PR_BYTES_PER_WORD_LOG2 2
#define PR_BYTES_PER_DWORD_LOG2 3
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 32
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 32
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 5
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 5
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 4
#define PR_ALIGN_OF_INT64 8
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 8
#define PR_ALIGN_OF_POINTER 4
#elif defined(__alpha__)
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#define HAVE_ALIGNED_DOUBLES
#define HAVE_ALIGNED_LONGLONGS
#define IS_64
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 8
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 8
#define PR_BYTES_PER_DWORD 8
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 64
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 64
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 6
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 6
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 8
#define PR_ALIGN_OF_INT64 8
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 8
#define PR_ALIGN_OF_POINTER 8
#define PR_BYTES_PER_WORD_LOG2 3
#define PR_BYTES_PER_DWORD_LOG2 3
#elif defined(__powerpc__) || defined(__m68k__)
#undef IS_LITTLE_ENDIAN
#define IS_BIG_ENDIAN 1
#undef HAVE_ALIGNED_DOUBLES
#undef HAVE_ALIGNED_LONGLONGS
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 4
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 4
#define PR_BYTES_PER_DWORD 8
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 32
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 32
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 5
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 5
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 4
#define PR_ALIGN_OF_INT64 4
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 4
#define PR_ALIGN_OF_POINTER 4
#define PR_BYTES_PER_WORD_LOG2 2
#define PR_BYTES_PER_DWORD_LOG2 3
#elif defined(__mips__)
#ifdef __MIPSEB__
#define IS_BIG_ENDIAN 1
#undef IS_LITTLE_ENDIAN
#elif defined(__MIPSEL__)
#define IS_LITTLE_ENDIAN 1
#undef IS_BIG_ENDIAN
#else
#error "Unknown MIPS endianness."
#endif
#define PR_BYTES_PER_BYTE 1
#define PR_BYTES_PER_SHORT 2
#define PR_BYTES_PER_INT 4
#define PR_BYTES_PER_INT64 8
#define PR_BYTES_PER_LONG 8
#define PR_BYTES_PER_FLOAT 4
#define PR_BYTES_PER_DOUBLE 8
#define PR_BYTES_PER_WORD 4
#define PR_BYTES_PER_DWORD 8
#define PR_BITS_PER_BYTE 8
#define PR_BITS_PER_SHORT 16
#define PR_BITS_PER_INT 32
#define PR_BITS_PER_INT64 64
#define PR_BITS_PER_LONG 64
#define PR_BITS_PER_FLOAT 32
#define PR_BITS_PER_DOUBLE 64
#define PR_BITS_PER_WORD 64
#define PR_BITS_PER_BYTE_LOG2 3
#define PR_BITS_PER_SHORT_LOG2 4
#define PR_BITS_PER_INT_LOG2 5
#define PR_BITS_PER_INT64_LOG2 6
#define PR_BITS_PER_LONG_LOG2 5
#define PR_BITS_PER_FLOAT_LOG2 5
#define PR_BITS_PER_DOUBLE_LOG2 6
#define PR_BITS_PER_WORD_LOG2 5
#define PR_ALIGN_OF_SHORT 2
#define PR_ALIGN_OF_INT 4
#define PR_ALIGN_OF_LONG 4
#define PR_ALIGN_OF_INT64 8
#define PR_ALIGN_OF_FLOAT 4
#define PR_ALIGN_OF_DOUBLE 8
#define PR_ALIGN_OF_POINTER 4
#define PR_ALIGN_OF_WORD 4
#define PR_BYTES_PER_WORD_LOG2 2
#define PR_BYTES_PER_DWORD_LOG2 3
#else
#error Must define constants for type sizes here.
#endif
#ifndef NO_NSPR_10_SUPPORT
#define BYTES_PER_BYTE PR_BYTES_PER_BYTE
#define BYTES_PER_SHORT PR_BYTES_PER_SHORT
#define BYTES_PER_INT PR_BYTES_PER_INT
#define BYTES_PER_INT64 PR_BYTES_PER_INT64
#define BYTES_PER_LONG PR_BYTES_PER_LONG
#define BYTES_PER_FLOAT PR_BYTES_PER_FLOAT
#define BYTES_PER_DOUBLE PR_BYTES_PER_DOUBLE
#define BYTES_PER_WORD PR_BYTES_PER_WORD
#define BYTES_PER_DWORD PR_BYTES_PER_DWORD
#define BITS_PER_BYTE PR_BITS_PER_BYTE
#define BITS_PER_SHORT PR_BITS_PER_SHORT
#define BITS_PER_INT PR_BITS_PER_INT
#define BITS_PER_INT64 PR_BITS_PER_INT64
#define BITS_PER_LONG PR_BITS_PER_LONG
#define BITS_PER_FLOAT PR_BITS_PER_FLOAT
#define BITS_PER_DOUBLE PR_BITS_PER_DOUBLE
#define BITS_PER_WORD PR_BITS_PER_WORD
#define BITS_PER_BYTE_LOG2 PR_BITS_PER_BYTE_LOG2
#define BITS_PER_SHORT_LOG2 PR_BITS_PER_SHORT_LOG2
#define BITS_PER_INT_LOG2 PR_BITS_PER_INT_LOG2
#define BITS_PER_INT64_LOG2 PR_BITS_PER_INT64_LOG2
#define BITS_PER_LONG_LOG2 PR_BITS_PER_LONG_LOG2
#define BITS_PER_FLOAT_LOG2 PR_BITS_PER_FLOAT_LOG2
#define BITS_PER_DOUBLE_LOG2 PR_BITS_PER_DOUBLE_LOG2
#define BITS_PER_WORD_LOG2 PR_BITS_PER_WORD_LOG2
#define ALIGN_OF_SHORT PR_ALIGN_OF_SHORT
#define ALIGN_OF_INT PR_ALIGN_OF_INT
#define ALIGN_OF_LONG PR_ALIGN_OF_LONG
#define ALIGN_OF_INT64 PR_ALIGN_OF_INT64
#define ALIGN_OF_FLOAT PR_ALIGN_OF_FLOAT
#define ALIGN_OF_DOUBLE PR_ALIGN_OF_DOUBLE
#define ALIGN_OF_POINTER PR_ALIGN_OF_POINTER
#define ALIGN_OF_WORD PR_ALIGN_OF_WORD
#define BYTES_PER_WORD_LOG2 PR_BYTES_PER_WORD_LOG2
#define BYTES_PER_DWORD_LOG2 PR_BYTES_PER_DWORD_LOG2
#define WORDS_PER_DWORD_LOG2 PR_WORDS_PER_DWORD_LOG2
#endif /* NO_NSPR_10_SUPPORT */
#endif /* nspr_cpucfg___ */

View File

@ -164,7 +164,7 @@ TimeTicks TimeTicks::Now() {
// With numer and denom = 1 (the expected case), the 64-bit absolute time
// reported in nanoseconds is enough to last nearly 585 years.
#elif defined(OS_POSIX) && \
#elif defined(__OpenBSD__) || defined(OS_POSIX) && \
defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
struct timespec ts;

View File

@ -19,6 +19,8 @@
#define OS_MACOSX 1
#elif defined(__linux__) || defined(ANDROID)
#define OS_LINUX 1
#elif defined(__OpenBSD__)
#define OS_OPENBSD 1
#elif defined(_WIN32)
#define OS_WIN 1
#else
@ -27,7 +29,7 @@
// For access to standard POSIX features, use OS_POSIX instead of a more
// specific macro.
#if defined(OS_MACOSX) || defined(OS_LINUX)
#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_OPENBSD)
#define OS_POSIX 1
#endif
@ -60,6 +62,9 @@
#elif defined(__ppc__) || defined(__powerpc__)
#define ARCH_CPU_PPC 1
#define ARCH_CPU_32_BITS 1
#elif defined(__sparc64__)
#define ARCH_CPU_SPARC 1
#define ARCH_CPU_64_BITS 1
#else
#error Please add support for your architecture in build/build_config.h
#endif

View File

@ -11,6 +11,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <string>
#include <map>

File diff suppressed because it is too large Load Diff

View File

@ -58,7 +58,7 @@ BEGIN_TEST(testGCOutOfMemory)
}
virtual JSRuntime * createRuntime() {
return JS_NewRuntime(256 * 1024);
return JS_NewRuntime(512 * 1024);
}
virtual void destroyRuntime() {

View File

@ -56,7 +56,7 @@ BEGIN_TEST(testIndexToString)
JSString *str = js::IndexToString(cx, u);
CHECK(str);
if (!JSAtom::hasUintStatic(u))
if (!js::StaticStrings::hasUint(u))
CHECK(cx->compartment->dtoaCache.lookup(10, u) == str);
JSBool match = JS_FALSE;

View File

@ -11,28 +11,28 @@ BEGIN_TEST(testIntString_bug515273)
EVAL("'1';", v.addr());
JSString *str = JSVAL_TO_STRING(v.value());
CHECK(str->isStaticAtom());
CHECK(JS_StringHasBeenInterned(cx, str));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "1"));
EVAL("'42';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(str->isStaticAtom());
CHECK(JS_StringHasBeenInterned(cx, str));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "42"));
EVAL("'111';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(str->isStaticAtom());
CHECK(JS_StringHasBeenInterned(cx, str));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "111"));
/* Test other types of static strings. */
EVAL("'a';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(str->isStaticAtom());
CHECK(JS_StringHasBeenInterned(cx, str));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "a"));
EVAL("'bc';", v.addr());
str = JSVAL_TO_STRING(v.value());
CHECK(str->isStaticAtom());
CHECK(JS_StringHasBeenInterned(cx, str));
CHECK(JS_FlatStringEqualsAscii(JS_ASSERT_STRING_IS_FLAT(str), "bc"));
return true;

View File

@ -423,7 +423,7 @@ js_SweepAtomState(JSContext *cx)
JS_ASSERT(!IsAboutToBeFinalized(cx, entry.asPtr()));
continue;
}
if (IsAboutToBeFinalized(cx, entry.asPtr()))
e.removeFront();
}
@ -432,7 +432,8 @@ js_SweepAtomState(JSContext *cx)
bool
AtomIsInterned(JSContext *cx, JSAtom *atom)
{
if (atom->isStaticAtom())
/* We treat static strings as interned because they're never collected. */
if (StaticStrings::isStatic(atom))
return true;
AutoLockAtomsCompartment lock(cx);
@ -461,7 +462,7 @@ AtomizeInline(JSContext *cx, const jschar **pchars, size_t length,
{
const jschar *chars = *pchars;
if (JSAtom *s = JSAtom::lookupStatic(chars, length))
if (JSAtom *s = cx->runtime->staticStrings.lookup(chars, length))
return s;
AutoLockAtomsCompartment lock(cx);
@ -521,7 +522,7 @@ js_AtomizeString(JSContext *cx, JSString *str, InternBehavior ib)
if (str->isAtom()) {
JSAtom &atom = str->asAtom();
/* N.B. static atoms are effectively always interned. */
if (ib != InternAtom || atom.isStaticAtom())
if (ib != InternAtom || js::StaticStrings::isStatic(&atom))
return &atom;
/* Here we have to check whether the atom is already interned. */
@ -604,7 +605,7 @@ js_AtomizeChars(JSContext *cx, const jschar *chars, size_t length, InternBehavio
JSAtom *
js_GetExistingStringAtom(JSContext *cx, const jschar *chars, size_t length)
{
if (JSAtom *atom = JSAtom::lookupStatic(chars, length))
if (JSAtom *atom = cx->runtime->staticStrings.lookup(chars, length))
return atom;
AutoLockAtomsCompartment lock(cx);
AtomSet::Ptr p = cx->runtime->atomState.atoms.lookup(AtomHasher::Lookup(chars, length));

View File

@ -406,7 +406,9 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
#ifdef JS_THREADSAFE
JS_BeginRequest(cx);
#endif
JSBool ok = js_InitCommonAtoms(cx);
bool ok = rt->staticStrings.init(cx);
if (ok)
ok = js_InitCommonAtoms(cx);
#ifdef JS_THREADSAFE
JS_EndRequest(cx);

View File

@ -65,6 +65,7 @@
#include "prmjtime.h"
#include "vm/Stack.h"
#include "vm/String.h"
#ifdef _MSC_VER
#pragma warning(push)
@ -655,6 +656,9 @@ struct JSRuntime {
/* Literal table maintained by jsatom.c functions. */
JSAtomState atomState;
/* Tables of strings that are pre-allocated in the atomsCompartment. */
js::StaticStrings staticStrings;
JSWrapObjectCallback wrapObjectCallback;
JSPreWrapCallback preWrapObjectCallback;

View File

@ -207,10 +207,6 @@ JSCompartment::wrap(JSContext *cx, Value *vp)
if (vp->isString()) {
JSString *str = vp->toString();
/* Static atoms do not have to be wrapped. */
if (str->isStaticAtom())
return true;
/* If the string is already in this compartment, we are done. */
if (str->compartment() == this)
return true;

View File

@ -450,9 +450,8 @@ Chunk::removeFromAvailableList()
}
ArenaHeader *
Chunk::allocateArena(JSContext *cx, AllocKind thingKind)
Chunk::allocateArena(JSCompartment *comp, AllocKind thingKind)
{
JSCompartment *comp = cx->compartment;
JS_ASSERT(hasAvailableArenas());
ArenaHeader *aheader = info.emptyArenaListHead;
info.emptyArenaListHead = aheader->next;
@ -547,9 +546,8 @@ ReleaseGCChunk(JSRuntime *rt, Chunk *p)
/* The caller must hold the GC lock. */
static Chunk *
PickChunk(JSContext *cx)
PickChunk(JSCompartment *comp)
{
JSCompartment *comp = cx->compartment;
JSRuntime *rt = comp->rt;
Chunk **listHeadp = GetAvailableChunkList(comp);
Chunk *chunk = *listHeadp;
@ -621,8 +619,6 @@ ExpireGCChunks(JSRuntime *rt, JSGCInvocationKind gckind)
JS_FRIEND_API(bool)
IsAboutToBeFinalized(JSContext *cx, const void *thing)
{
if (JSAtom::isStatic(thing))
return false;
JS_ASSERT(cx);
JSCompartment *thingCompartment = reinterpret_cast<const Cell *>(thing)->compartment();
@ -639,7 +635,6 @@ js_GCThingIsMarked(void *thing, uintN color = BLACK)
{
JS_ASSERT(thing);
AssertValidColor(thing, color);
JS_ASSERT(!JSAtom::isStatic(thing));
return reinterpret_cast<Cell *>(thing)->isMarked(color);
}
@ -1148,7 +1143,7 @@ namespace js {
namespace gc {
inline void *
ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
ArenaLists::allocateFromArena(JSCompartment *comp, AllocKind thingKind)
{
Chunk *chunk = NULL;
@ -1163,7 +1158,7 @@ ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
* background finalization runs and can modify head or cursor at any
* moment. So we always allocate a new arena in that case.
*/
maybeLock.lock(cx->runtime);
maybeLock.lock(comp->rt);
for (;;) {
if (*bfs == BFS_DONE)
break;
@ -1179,7 +1174,7 @@ ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
}
JS_ASSERT(!*al->cursor);
chunk = PickChunk(cx);
chunk = PickChunk(comp);
if (chunk)
break;
@ -1189,7 +1184,7 @@ ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
* added new empty arenas.
*/
JS_ASSERT(*bfs == BFS_RUN);
cx->runtime->gcHelperThread.waitBackgroundSweepEnd(cx->runtime, false);
comp->rt->gcHelperThread.waitBackgroundSweepEnd(comp->rt, false);
JS_ASSERT(*bfs == BFS_JUST_FINISHED || *bfs == BFS_DONE);
}
}
@ -1217,8 +1212,8 @@ ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
/* Make sure we hold the GC lock before we call PickChunk. */
if (!maybeLock.locked())
maybeLock.lock(cx->runtime);
chunk = PickChunk(cx);
maybeLock.lock(comp->rt);
chunk = PickChunk(comp);
if (!chunk)
return NULL;
}
@ -1233,7 +1228,7 @@ ArenaLists::allocateFromArena(JSContext *cx, AllocKind thingKind)
* for allocations improving cache locality.
*/
JS_ASSERT(!*al->cursor);
ArenaHeader *aheader = chunk->allocateArena(cx, thingKind);
ArenaHeader *aheader = chunk->allocateArena(comp, thingKind);
aheader->next = al->head;
if (!al->head) {
JS_ASSERT(al->cursor == &al->head);
@ -1436,14 +1431,9 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
{
JS_ASSERT(cx->compartment->arenas.freeLists[thingKind].isEmpty());
/*
* For compatibility with older code we tolerate calling the allocator
* during the GC in optimized builds.
*/
JSRuntime *rt = cx->runtime;
JSCompartment *comp = cx->compartment;
JSRuntime *rt = comp->rt;
JS_ASSERT(!rt->gcRunning);
if (rt->gcRunning)
return NULL;
bool runGC = !!rt->gcIsNeeded;
for (;;) {
@ -1460,10 +1450,10 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
* return that list head.
*/
size_t thingSize = Arena::thingSize(thingKind);
if (void *thing = cx->compartment->arenas.allocateFromFreeList(thingKind, thingSize))
if (void *thing = comp->arenas.allocateFromFreeList(thingKind, thingSize))
return thing;
}
void *thing = cx->compartment->arenas.allocateFromArena(cx, thingKind);
void *thing = comp->arenas.allocateFromArena(comp, thingKind);
if (JS_LIKELY(!!thing))
return thing;
@ -1640,24 +1630,22 @@ gc_root_traversal(JSTracer *trc, const RootEntry &entry)
}
if (ptr && !trc->context->runtime->gcCurrentCompartment) {
if (!JSAtom::isStatic(ptr)) {
/*
* Use conservative machinery to find if ptr is a valid GC thing.
* We only do this during global GCs, to preserve the invariant
* that mark callbacks are not in place during compartment GCs.
*/
JSTracer checker;
JS_TRACER_INIT(&checker, trc->context, EmptyMarkCallback);
ConservativeGCTest test = MarkIfGCThingWord(&checker, reinterpret_cast<jsuword>(ptr));
if (test != CGCT_VALID && entry.value.name) {
fprintf(stderr,
/*
* Use conservative machinery to find if ptr is a valid GC thing.
* We only do this during global GCs, to preserve the invariant
* that mark callbacks are not in place during compartment GCs.
*/
JSTracer checker;
JS_TRACER_INIT(&checker, trc->context, EmptyMarkCallback);
ConservativeGCTest test = MarkIfGCThingWord(&checker, reinterpret_cast<jsuword>(ptr));
if (test != CGCT_VALID && entry.value.name) {
fprintf(stderr,
"JS API usage error: the address passed to JS_AddNamedRoot currently holds an\n"
"invalid gcthing. This is usually caused by a missing call to JS_RemoveRoot.\n"
"The root's name is \"%s\".\n",
entry.value.name);
}
JS_ASSERT(test == CGCT_VALID);
entry.value.name);
}
JS_ASSERT(test == CGCT_VALID);
}
#endif
JS_SET_TRACING_NAME(trc, entry.value.name ? entry.value.name : "root");
@ -1856,6 +1844,7 @@ MarkRuntime(JSTracer *trc)
gc_lock_traversal(r.front(), trc);
js_TraceAtomState(trc);
rt->staticStrings.trace(trc);
JSContext *iter = NULL;
while (JSContext *acx = js_ContextIterator(rt, JS_TRUE, &iter))

View File

@ -654,7 +654,7 @@ struct Chunk {
inline void addToAvailableList(JSCompartment *compartment);
inline void removeFromAvailableList();
ArenaHeader *allocateArena(JSContext *cx, AllocKind kind);
ArenaHeader *allocateArena(JSCompartment *comp, AllocKind kind);
void releaseArena(ArenaHeader *aheader);
};
@ -1102,7 +1102,7 @@ struct ArenaLists {
inline void finalizeNow(JSContext *cx, AllocKind thingKind);
inline void finalizeLater(JSContext *cx, AllocKind thingKind);
inline void *allocateFromArena(JSContext *cx, AllocKind thingKind);
inline void *allocateFromArena(JSCompartment *comp, AllocKind thingKind);
};
/*

View File

@ -49,63 +49,6 @@
#include "jslock.h"
#include "jstl.h"
inline bool
JSAtom::isUnitString(const void *ptr)
{
#ifdef JS_HAS_STATIC_STRINGS
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(unitStaticTable);
if (delta >= UNIT_STATIC_LIMIT * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
#else
return false;
#endif
}
inline bool
JSAtom::isLength2String(const void *ptr)
{
#ifdef JS_HAS_STATIC_STRINGS
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(length2StaticTable);
if (delta >= NUM_SMALL_CHARS * NUM_SMALL_CHARS * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
#else
return false;
#endif
}
inline bool
JSAtom::isHundredString(const void *ptr)
{
#ifdef JS_HAS_STATIC_STRINGS
jsuword delta = reinterpret_cast<jsuword>(ptr) -
reinterpret_cast<jsuword>(hundredStaticTable);
if (delta >= NUM_HUNDRED_STATICS * sizeof(JSString))
return false;
/* If ptr points inside the static array, it must be well-aligned. */
JS_ASSERT(delta % sizeof(JSString) == 0);
return true;
#else
return false;
#endif
}
inline bool
JSAtom::isStatic(const void *ptr)
{
return isUnitString(ptr) || isLength2String(ptr) || isHundredString(ptr);
}
namespace js {
struct Shape;
@ -116,8 +59,6 @@ inline JSGCTraceKind
GetGCThingTraceKind(const void *thing)
{
JS_ASSERT(thing);
if (JSAtom::isStatic(thing))
return JSTRACE_STRING;
const Cell *cell = reinterpret_cast<const Cell *>(thing);
return MapAllocToTraceKind(cell->getAllocKind());
}

View File

@ -115,7 +115,6 @@ CheckMarkedThing(JSTracer *trc, T *thing)
JS_ASSERT(trc->debugPrinter || trc->debugPrintArg);
JS_ASSERT_IF(trc->context->runtime->gcCurrentCompartment, IS_GC_MARKING_TRACER(trc));
JS_ASSERT(!JSAtom::isStatic(thing));
JS_ASSERT(thing->isAligned());
JS_ASSERT(thing->compartment());
@ -155,8 +154,6 @@ void
MarkString(JSTracer *trc, JSString *str)
{
JS_ASSERT(str);
if (str->isStaticAtom())
return;
Mark(trc, str);
}
@ -334,8 +331,7 @@ MarkAtomRange(JSTracer *trc, size_t len, JSAtom **vec, const char *name)
for (uint32 i = 0; i < len; i++) {
if (JSAtom *atom = vec[i]) {
JS_SET_TRACING_INDEX(trc, name, i);
if (!atom->isStaticAtom())
Mark(trc, atom);
Mark(trc, atom);
}
}
}
@ -365,13 +361,10 @@ MarkXMLRange(JSTracer *trc, size_t len, JSXML **vec, const char *name)
void
MarkId(JSTracer *trc, jsid id)
{
if (JSID_IS_STRING(id)) {
JSString *str = JSID_TO_STRING(id);
if (!str->isStaticAtom())
Mark(trc, str);
} else if (JS_UNLIKELY(JSID_IS_OBJECT(id))) {
if (JSID_IS_STRING(id))
Mark(trc, JSID_TO_STRING(id));
else if (JS_UNLIKELY(JSID_IS_OBJECT(id)))
Mark(trc, JSID_TO_OBJECT(id));
}
}
void
@ -447,9 +440,6 @@ MarkCrossCompartmentValue(JSTracer *trc, const js::Value &v, const char *name)
{
if (v.isMarkable()) {
js::gc::Cell *cell = (js::gc::Cell *)v.toGCThing();
unsigned kind = v.gcKind();
if (kind == JSTRACE_STRING && ((JSString *)cell)->isStaticAtom())
return;
JSRuntime *rt = trc->context->runtime;
if (rt->gcCurrentCompartment && cell->compartment() != rt->gcCurrentCompartment)
return;
@ -604,12 +594,10 @@ ScanValue(GCMarker *gcmarker, const Value &v)
if (v.isMarkable()) {
JSGCTraceKind kind = v.gcKind();
if (kind == JSTRACE_STRING) {
JSString *str = (JSString *)v.toGCThing();
if (!str->isStaticAtom())
PushMarkStack(gcmarker, str);
PushMarkStack(gcmarker, v.toString());
} else {
JS_ASSERT(kind == JSTRACE_OBJECT);
PushMarkStack(gcmarker, (JSObject *)v.toGCThing());
PushMarkStack(gcmarker, &v.toObject());
}
}
}
@ -622,13 +610,10 @@ restart:
if (rt->gcRegenShapes)
shape->shapeid = js_RegenerateShapeForGC(rt);
if (JSID_IS_STRING(shape->propid)) {
JSString *str = JSID_TO_STRING(shape->propid);
if (!str->isStaticAtom())
PushMarkStack(gcmarker, str);
} else if (JS_UNLIKELY(JSID_IS_OBJECT(shape->propid))) {
if (JSID_IS_STRING(shape->propid))
PushMarkStack(gcmarker, JSID_TO_STRING(shape->propid));
else if (JS_UNLIKELY(JSID_IS_OBJECT(shape->propid)))
PushMarkStack(gcmarker, JSID_TO_OBJECT(shape->propid));
}
if (shape->hasGetterValue() && shape->getter())
PushMarkStack(gcmarker, shape->getterObject());
@ -894,11 +879,8 @@ ScanTypeObject(GCMarker *gcmarker, types::TypeObject *type)
unsigned count = type->getPropertyCount();
for (unsigned i = 0; i < count; i++) {
types::Property *prop = type->getProperty(i);
if (prop && JSID_IS_STRING(prop->id)) {
JSString *str = JSID_TO_STRING(prop->id);
if (!str->isStaticAtom())
PushMarkStack(gcmarker, str);
}
if (prop && JSID_IS_STRING(prop->id))
PushMarkStack(gcmarker, JSID_TO_STRING(prop->id));
}
}

View File

@ -5937,7 +5937,7 @@ TypeCompartment::sweep(JSContext *cx)
for (unsigned i = 0; !remove && i < key.nslots; i++) {
if (JSID_IS_STRING(key.ids[i])) {
JSString *str = JSID_TO_STRING(key.ids[i]);
if (!str->isStaticAtom() && !str->isMarked())
if (!str->isMarked())
remove = true;
}
JS_ASSERT(!entry.types[i].isSingleObject());
@ -6031,7 +6031,6 @@ TypeScript::Sweep(JSContext *cx, JSScript *script)
*/
#ifdef JS_METHODJIT
mjit::ReleaseScriptCode(cx, script);
#endif
/*
* Use counts for scripts are reset on GC. After discarding code we need to
@ -6039,6 +6038,7 @@ TypeScript::Sweep(JSContext *cx, JSScript *script)
* array holes or accessing getter properties.
*/
script->resetUseCount();
#endif
}
void

View File

@ -3837,7 +3837,7 @@ BEGIN_CASE(JSOP_GETELEM)
JSString *str = lref.toString();
int32_t i = rref.toInt32();
if (size_t(i) < str->length()) {
str = JSAtom::getUnitStringForElement(cx, str, size_t(i));
str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
if (!str)
goto error;
regs.sp--;
@ -4966,7 +4966,7 @@ BEGIN_CASE(JSOP_GETTER)
BEGIN_CASE(JSOP_SETTER)
{
do_getter_setter:
JSOp op2 = (JSOp) *++regs.pc;
JSOp op2 = js_GetOpcode(cx, script, ++regs.pc);
jsid id;
Value rval;
jsint i;

View File

@ -1025,8 +1025,8 @@ js_IteratorNext(JSContext *cx, JSObject *iterobj, Value *rval)
JSString *str;
jsint i;
if (rval->isInt32() && JSAtom::hasIntStatic(i = rval->toInt32())) {
str = &JSAtom::intStatic(i);
if (rval->isInt32() && StaticStrings::hasInt(i = rval->toInt32())) {
str = cx->runtime->staticStrings.getInt(i);
} else {
str = js_ValueToString(cx, *rval);
if (!str)

View File

@ -637,8 +637,8 @@ js_IntToString(JSContext *cx, int32 si)
{
uint32 ui;
if (si >= 0) {
if (JSAtom::hasIntStatic(si))
return &JSAtom::intStatic(si);
if (StaticStrings::hasInt(si))
return cx->runtime->staticStrings.getInt(si);
ui = si;
} else {
ui = uint32(-si);
@ -1204,17 +1204,15 @@ js_NumberToStringWithBase(JSContext *cx, jsdouble d, jsint base)
int32_t i;
if (JSDOUBLE_IS_INT32(d, &i)) {
if (base == 10 && JSAtom::hasIntStatic(i))
return &JSAtom::intStatic(i);
#ifdef JS_HAS_STATIC_STRINGS
if (base == 10 && StaticStrings::hasInt(i))
return cx->runtime->staticStrings.getInt(i);
if (jsuint(i) < jsuint(base)) {
if (i < 10)
return &JSAtom::intStatic(i);
return cx->runtime->staticStrings.getInt(i);
jschar c = 'a' + i - 10;
JS_ASSERT(JSAtom::hasUnitStatic(c));
return &JSAtom::unitStatic(c);
JS_ASSERT(StaticStrings::hasUnit(c));
return cx->runtime->staticStrings.getUnit(c);
}
#endif
if (JSFlatString *str = c->dtoaCache.lookup(base, d))
return str;
@ -1260,8 +1258,8 @@ NumberToString(JSContext *cx, jsdouble d)
JSFixedString *
IndexToString(JSContext *cx, uint32 index)
{
if (JSAtom::hasUintStatic(index))
return &JSAtom::uintStatic(index);
if (StaticStrings::hasUint(index))
return cx->runtime->staticStrings.getUint(index);
JSCompartment *c = cx->compartment;
if (JSFixedString *str = c->dtoaCache.lookup(10, index))

View File

@ -148,24 +148,24 @@ uintN
js_GetIndexFromBytecode(JSContext *cx, JSScript *script, jsbytecode *pc,
ptrdiff_t pcoff)
{
JSOp op;
uintN span, base;
op = js_GetOpcode(cx, script, pc);
JSOp op = js_GetOpcode(cx, script, pc);
JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
/*
* We need to detect index base prefix. It presents when resetbase
* follows the bytecode.
*/
span = js_CodeSpec[op].length;
base = 0;
uintN span = js_CodeSpec[op].length;
uintN base = 0;
if (pc - script->code + span < script->length) {
if (pc[span] == JSOP_RESETBASE) {
JSOp next = js_GetOpcode(cx, script, pc + span);
if (next == JSOP_RESETBASE) {
JS_ASSERT(js_GetOpcode(cx, script, pc - JSOP_INDEXBASE_LENGTH) == JSOP_INDEXBASE);
base = GET_INDEXBASE(pc - JSOP_INDEXBASE_LENGTH);
} else if (pc[span] == JSOP_RESETBASE0) {
JS_ASSERT(JSOP_INDEXBASE1 <= pc[-1] || pc[-1] <= JSOP_INDEXBASE3);
base = (pc[-1] - JSOP_INDEXBASE1 + 1) << 16;
} else if (next == JSOP_RESETBASE0) {
JSOp prev = js_GetOpcode(cx, script, pc - 1);
JS_ASSERT(JSOP_INDEXBASE1 <= prev && prev <= JSOP_INDEXBASE3);
base = (prev - JSOP_INDEXBASE1 + 1) << 16;
}
}
return base + GET_UINT16(pc + pcoff);

View File

@ -224,7 +224,8 @@ typedef enum JSOp {
#define GET_INDEX(pc) GET_UINT16(pc)
#define SET_INDEX(pc,i) ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i))
#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE), \
#define GET_INDEXBASE(pc) (JS_ASSERT(*(pc) == JSOP_INDEXBASE \
|| *(pc) == JSOP_TRAP), \
((uintN)((pc)[1])) << 16)
#define INDEXBASE_LEN 1

View File

@ -372,7 +372,7 @@ str_resolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
jsint slot = JSID_TO_INT(id);
if ((size_t)slot < str->length()) {
JSString *str1 = JSAtom::getUnitStringForElement(cx, str, size_t(slot));
JSString *str1 = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(slot));
if (!str1)
return JS_FALSE;
if (!obj->defineElement(cx, uint32(slot), StringValue(str1), NULL, NULL,
@ -730,7 +730,7 @@ js_str_charAt(JSContext *cx, uintN argc, Value *vp)
i = (jsint) d;
}
str = JSAtom::getUnitStringForElement(cx, str, size_t(i));
str = cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
if (!str)
return false;
vp->setString(str);
@ -2611,7 +2611,7 @@ str_slice(JSContext *cx, uintN argc, Value *vp)
str = cx->runtime->emptyString;
} else {
str = (length == 1)
? JSAtom::getUnitStringForElement(cx, str, begin)
? cx->runtime->staticStrings.getUnitStringForElement(cx, str, begin)
: js_NewDependentString(cx, str, begin, length);
if (!str)
return JS_FALSE;
@ -2829,7 +2829,7 @@ js_String_getelem(JSContext* cx, JSString* str, int32 i)
{
if ((size_t)i >= str->length())
return NULL;
return JSAtom::getUnitStringForElement(cx, str, size_t(i));
return cx->runtime->staticStrings.getUnitStringForElement(cx, str, size_t(i));
}
#endif
@ -2893,204 +2893,6 @@ static JSFunctionSpec string_methods[] = {
JS_FS_END
};
#ifdef JS_HAS_STATIC_STRINGS
/*
* Set up some tools to make it easier to generate large tables. After constant
* folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
* Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
* To use this, define R appropriately, then use Rn(0) (for some value of n), then
* undefine R.
*/
#define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
#define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
#define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
#define R8(n) R6(n), R6((n) + (1 << 6)), R6((n) + (2 << 6)), R6((n) + (3 << 6))
#define R10(n) R8(n), R8((n) + (1 << 8)), R8((n) + (2 << 8)), R8((n) + (3 << 8))
#define R12(n) R10(n), R10((n) + (1 << 10)), R10((n) + (2 << 10)), R10((n) + (3 << 10))
#define R3(n) R2(n), R2((n) + (1 << 2))
#define R7(n) R6(n), R6((n) + (1 << 6))
#define BUILD_LENGTH_AND_FLAGS(length, flags) \
(((length) << JSString::LENGTH_SHIFT) | (flags))
/*
* Declare unit strings. Pack the string data itself into the mInlineChars
* place in the header.
*/
#define R(c) { \
BUILD_LENGTH_AND_FLAGS(1, JSString::STATIC_ATOM_FLAGS), \
{ (jschar *)(uintptr_t(unitStaticTable + (c)) + \
offsetof(JSString::Data, inlineStorage)) }, \
{ {(c), 0x00} } }
/*
* For all the pragma pack usage in this file, the following logic applies:
* To apply: To reset:
* Sun CC: pack(#) / pack(0)
* IBM xlC: pack(#) / pack(pop)
* HP aCC: pack # / pack
* Others: pack(push, #) / pack(pop)
* The -Dlint case is explicitly excluded because GCC will error out when
* pack pragmas are used on unsupported platforms. If GCC is being used
* simply for error checking, these errors will be avoided.
*/
#if defined(__SUNPRO_CC) || defined(__xlC__)
#pragma pack(8)
#elif defined(__HP_aCC)
#pragma pack 8
#elif !defined(lint)
#pragma pack(push, 8)
#endif
const JSString::Data JSAtom::unitStaticTable[]
#if defined(__GNUC__) || defined(__xlC__)
__attribute__ ((aligned (8)))
#endif
= { R8(0) };
#if defined(__SUNPRO_CC)
#pragma pack(0)
#elif defined(__HP_aCC)
#pragma pack
#elif !defined(lint)
#pragma pack(pop)
#endif
#undef R
/*
* Declare length-2 strings. We only store strings where both characters are
* alphanumeric. The lower 10 short chars are the numerals, the next 26 are
* the lowercase letters, and the next 26 are the uppercase letters.
*/
#define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
(c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
(c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
JSAtom::INVALID_SMALL_CHAR)
#define R TO_SMALL_CHAR
const JSAtom::SmallChar JSAtom::toSmallChar[] = { R7(0) };
#undef R
/*
* This is used when we generate our table of short strings, so the compiler is
* happier if we use |c| as few times as possible.
*/
#define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
(c) < 36 ? 'a' - 10 : \
'A' - 36))
#define R FROM_SMALL_CHAR
const jschar JSAtom::fromSmallChar[] = { R6(0) };
#undef R
/*
* For code-generation ease, length-2 strings are encoded as 12-bit int values,
* where the upper 6 bits is the first character and the lower 6 bits is the
* second character.
*/
#define R(c) { \
BUILD_LENGTH_AND_FLAGS(2, JSString::STATIC_ATOM_FLAGS), \
{ (jschar *)(uintptr_t(length2StaticTable + (c)) + \
offsetof(JSString::Data, inlineStorage)) }, \
{ {FROM_SMALL_CHAR((c) >> 6), FROM_SMALL_CHAR((c) & 0x3F), 0x00} } }
#if defined(__SUNPRO_CC) || defined(__xlC__)
#pragma pack(8)
#elif defined(__HP_aCC)
#pragma pack 8
#elif !defined(lint)
#pragma pack(push, 8)
#endif
const JSString::Data JSAtom::length2StaticTable[]
#if defined(__GNUC__) || defined(__xlC__)
__attribute__ ((aligned (8)))
#endif
= { R12(0) };
#if defined(__SUNPRO_CC)
#pragma pack(0)
#elif defined(__HP_aCC)
#pragma pack
#elif !defined(lint)
#pragma pack(pop)
#endif
#undef R
/*
* Declare int strings. Only int strings from 100 to 255 actually have to be
* generated, since the rest are either unit strings or length-2 strings. To
* avoid the runtime cost of figuring out where to look for the string for a
* particular integer, we precompute a table of JSString*s which refer to the
* correct location of the int string.
*/
#define R(c) { \
BUILD_LENGTH_AND_FLAGS(3, JSString::STATIC_ATOM_FLAGS), \
{ (jschar *)(uintptr_t(hundredStaticTable + ((c) - 100)) + \
offsetof(JSString::Data, inlineStorage)) }, \
{ {((c) / 100) + '0', ((c) / 10 % 10) + '0', ((c) % 10) + '0', 0x00} } }
JS_STATIC_ASSERT(100 + (1 << 7) + (1 << 4) + (1 << 3) + (1 << 2) == 256);
#if defined(__SUNPRO_CC) || defined(__xlC__)
#pragma pack(8)
#elif defined(__HP_aCC)
#pragma pack 8
#elif !defined(lint)
#pragma pack(push, 8)
#endif
const JSString::Data JSAtom::hundredStaticTable[]
#if defined(__GNUC__) || defined(__xlC__)
__attribute__ ((aligned (8)))
#endif
= { R7(100), /* 100 through 227 */
R4(100 + (1 << 7)), /* 228 through 243 */
R3(100 + (1 << 7) + (1 << 4)), /* 244 through 251 */
R2(100 + (1 << 7) + (1 << 4) + (1 << 3)) /* 252 through 255 */
};
#undef R
#define R(c) ((c) < 10 ? JSAtom::unitStaticTable + ((c) + '0') : \
(c) < 100 ? JSAtom::length2StaticTable + \
((size_t)TO_SMALL_CHAR(((c) / 10) + '0') << 6) + \
TO_SMALL_CHAR(((c) % 10) + '0') : \
JSAtom::hundredStaticTable + ((c) - 100))
const JSString::Data *const JSAtom::intStaticTable[] = { R8(0) };
#undef R
#if defined(__SUNPRO_CC)
#pragma pack(0)
#elif defined(__HP_aCC)
#pragma pack
#elif !defined(lint)
#pragma pack(pop)
#endif
#undef R2
#undef R4
#undef R6
#undef R8
#undef R10
#undef R12
#undef R3
#undef R7
#endif /* defined(JS_HAS_STATIC_STRINGS) */
JSBool
js_String(JSContext *cx, uintN argc, Value *vp)
{
@ -3125,8 +2927,8 @@ str_fromCharCode(JSContext *cx, uintN argc, Value *vp)
uint16_t code;
if (!ValueToUint16(cx, argv[0], &code))
return JS_FALSE;
if (JSAtom::hasUnitStatic(code)) {
vp->setString(&JSAtom::unitStatic(code));
if (StaticStrings::hasUnit(code)) {
vp->setString(cx->runtime->staticStrings.getUnit(code));
return JS_TRUE;
}
argv[0].setInt32(code);
@ -3158,8 +2960,8 @@ String_fromCharCode(JSContext* cx, int32 i)
{
JS_ASSERT(JS_ON_TRACE(cx));
jschar c = (jschar)i;
if (JSAtom::hasUnitStatic(c))
return &JSAtom::unitStatic(c);
if (StaticStrings::hasUnit(c))
return cx->runtime->staticStrings.getUnit(c);
return js_NewStringCopyN(cx, &c, 1);
}
#endif
@ -3375,7 +3177,7 @@ js_NewDependentString(JSContext *cx, JSString *baseArg, size_t start, size_t len
const jschar *chars = base->chars() + start;
if (JSLinearString *staticStr = JSAtom::lookupStatic(chars, length))
if (JSLinearString *staticStr = cx->runtime->staticStrings.lookup(chars, length))
return staticStr;
JSLinearString *s = JSDependentString::new_(cx, base, chars, length);

View File

@ -11516,22 +11516,6 @@ TraceRecorder::callNative(uintN argc, JSOp mode)
}
if (vp[1].isString()) {
JSString *str = vp[1].toString();
#ifdef JS_HAS_STATIC_STRINGS
if (native == js_str_charAt) {
jsdouble i = vp[2].toNumber();
if (JSDOUBLE_IS_NaN(i))
i = 0;
if (i < 0 || i >= str->length())
RETURN_STOP("charAt out of bounds");
LIns* str_ins = get(&vp[1]);
LIns* idx_ins = get(&vp[2]);
LIns* char_ins;
CHECK_STATUS(getCharAt(str, str_ins, idx_ins, mode, &char_ins));
set(&vp[0], char_ins);
pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
return RECORD_CONTINUE;
} else
#endif
if (native == js_str_charCodeAt) {
jsdouble i = vp[2].toNumber();
if (JSDOUBLE_IS_NaN(i))
@ -12879,53 +12863,6 @@ TraceRecorder::getCharCodeAt(JSString *str, LIns* str_ins, LIns* idx_ins, LIns**
JS_STATIC_ASSERT(sizeof(JSString) == 16 || sizeof(JSString) == 32);
#ifdef JS_HAS_STATIC_STRINGS
JS_REQUIRES_STACK LIns*
TraceRecorder::getUnitString(LIns* str_ins, LIns* idx_ins)
{
LIns *ch_ins = w.getStringChar(str_ins, idx_ins);
guard(true, w.ltuiN(ch_ins, JSAtom::UNIT_STATIC_LIMIT), MISMATCH_EXIT);
JS_STATIC_ASSERT(sizeof(JSString) == 16 || sizeof(JSString) == 32);
return w.addp(w.nameImmpNonGC(JSAtom::unitStaticTable),
w.lshpN(w.ui2p(ch_ins), (sizeof(JSString) == 16) ? 4 : 5));
}
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::getCharAt(JSString *str, LIns* str_ins, LIns* idx_ins, JSOp mode, LIns** out)
{
CHECK_STATUS(makeNumberInt32(idx_ins, &idx_ins));
idx_ins = w.ui2p(idx_ins);
LIns *lengthAndFlags_ins = w.ldpStringLengthAndFlags(str_ins);
if (MaybeBranch mbr = w.jt(w.eqp0(w.andp(lengthAndFlags_ins,
w.nameImmw(JSString::ROPE_BIT)))))
{
LIns *args[] = { str_ins, cx_ins };
LIns *ok_ins = w.call(&js_FlattenOnTrace_ci, args);
guard(false, w.eqi0(ok_ins), OOM_EXIT);
w.label(mbr);
}
LIns* inRange = w.ltup(idx_ins, w.rshupN(lengthAndFlags_ins, JSString::LENGTH_SHIFT));
if (mode == JSOP_GETELEM) {
guard(true, inRange, MISMATCH_EXIT);
*out = getUnitString(str_ins, idx_ins);
} else {
LIns *phi_ins = w.allocp(sizeof(JSString *));
w.stAlloc(w.nameImmpNonGC(cx->runtime->emptyString), phi_ins);
if (MaybeBranch mbr = w.jf(inRange)) {
LIns *unitstr_ins = getUnitString(str_ins, idx_ins);
w.stAlloc(unitstr_ins, phi_ins);
w.label(mbr);
}
*out = w.ldpAlloc(phi_ins);
}
return RECORD_CONTINUE;
}
#endif
// Typed array tracing depends on EXPANDED_LOADSTORE and F2I
#if NJ_EXPANDED_LOADSTORE_SUPPORTED && NJ_F2I_SUPPORTED
static bool OkToTraceTypedArrays = true;
@ -12959,21 +12896,6 @@ TraceRecorder::record_JSOP_GETELEM()
LIns* obj_ins = get(&lval);
LIns* idx_ins = get(&idx);
#ifdef JS_HAS_STATIC_STRINGS
// Special case for array-like access of strings.
if (lval.isString() && hasInt32Repr(idx)) {
if (call)
RETURN_STOP_A("JSOP_CALLELEM on a string");
int i = asInt32(idx);
if (size_t(i) >= lval.toString()->length())
RETURN_STOP_A("Invalid string index in JSOP_GETELEM");
LIns* char_ins;
CHECK_STATUS_A(getCharAt(lval.toString(), obj_ins, idx_ins, JSOP_GETELEM, &char_ins));
set(&lval, char_ins);
return ARECORD_CONTINUE;
}
#endif
if (lval.isPrimitive())
RETURN_STOP_A("JSOP_GETLEM on a primitive");
RETURN_IF_XML_A(lval);

View File

@ -1398,12 +1398,6 @@ class TraceRecorder
JS_REQUIRES_STACK RecordingStatus getCharCodeAt(JSString *str,
nanojit::LIns* str_ins, nanojit::LIns* idx_ins,
nanojit::LIns** out_ins);
#ifdef JS_HAS_STATIC_STRINGS
JS_REQUIRES_STACK nanojit::LIns* getUnitString(nanojit::LIns* str_ins, nanojit::LIns* idx_ins);
JS_REQUIRES_STACK RecordingStatus getCharAt(JSString *str,
nanojit::LIns* str_ins, nanojit::LIns* idx_ins,
JSOp mode, nanojit::LIns** out_ins);
#endif
JS_REQUIRES_STACK RecordingStatus initOrSetPropertyByName(nanojit::LIns* obj_ins,
Value* idvalp, Value* rvalp,

View File

@ -1148,7 +1148,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
/*
* Generate code testing whether an in memory value at address has a type
* in the specified set. Updates mismatches with any failure jumps. Assumes
* no data registers are live.
* that no temporary (caller save) registers are live.
*/
bool generateTypeCheck(JSContext *cx, Address address,
types::TypeSet *types, Vector<Jump> *mismatches)
@ -1198,8 +1198,7 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
if (count != 0) {
if (!mismatches->append(testObject(Assembler::NotEqual, address)))
return false;
Registers tempRegs(Registers::AvailRegs);
RegisterID reg = tempRegs.takeAnyReg().reg();
RegisterID reg = Registers::ArgReg1;
loadPayload(address, reg);

View File

@ -279,12 +279,13 @@ mjit::Compiler::compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMo
if (mode == GetChar) {
/* Slow path if there's no unit string for this character. */
Jump notUnitString = masm.branch32(Assembler::AboveOrEqual, reg2,
Imm32(JSAtom::UNIT_STATIC_LIMIT));
Imm32(StaticStrings::UNIT_STATIC_LIMIT));
stubcc.linkExit(notUnitString, Uses(3));
/* Load unit string in reg2. */
masm.lshiftPtr(Imm32(sizeof(JSString) == 16 ? 4 : 5), reg2);
masm.addPtr(ImmPtr(JSAtom::unitStaticTable), reg2);
masm.lshiftPtr(Imm32(sizeof(JSAtom *) == 4 ? 2 : 3), reg2);
masm.addPtr(ImmPtr(&cx->runtime->staticStrings.unitStaticTable), reg2);
masm.loadPtr(Address(reg2), reg2);
}
if (thisValue->isConstant())

View File

@ -1234,7 +1234,8 @@ class GetPropCompiler : public PICStubCompiler
if (!linker.init(f.cx))
THROW();
if (!linker.verifyRange(f.jit())) {
if (!linker.verifyRange(pic.lastCodeBlock(f.jit())) ||
!linker.verifyRange(f.jit())) {
disable("code memory is out of range");
return;
}

View File

@ -436,7 +436,7 @@ stubs::GetElem(VMFrame &f)
JSString *str = lref.toString();
int32_t i = rref.toInt32();
if ((size_t)i < str->length()) {
str = JSAtom::getUnitStringForElement(cx, str, (size_t)i);
str = f.cx->runtime->staticStrings.getUnitStringForElement(cx, str, (size_t)i);
if (!str)
THROW();
f.regs.sp[-2].setString(str);

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
@ -193,54 +193,53 @@ JSExternalString::new_(JSContext *cx, const jschar *chars, size_t length, intN t
return str;
}
#ifdef JS_HAS_STATIC_STRINGS
inline bool
JSAtom::fitsInSmallChar(jschar c)
js::StaticStrings::fitsInSmallChar(jschar c)
{
return c < SMALL_CHAR_LIMIT && toSmallChar[c] != INVALID_SMALL_CHAR;
}
inline bool
JSAtom::hasUnitStatic(jschar c)
js::StaticStrings::hasUnit(jschar c)
{
return c < UNIT_STATIC_LIMIT;
}
inline JSStaticAtom &
JSAtom::unitStatic(jschar c)
inline JSAtom *
js::StaticStrings::getUnit(jschar c)
{
JS_ASSERT(hasUnitStatic(c));
return (JSStaticAtom &)unitStaticTable[c];
JS_ASSERT(hasUnit(c));
return unitStaticTable[c];
}
inline bool
JSAtom::hasUintStatic(uint32 u)
js::StaticStrings::hasUint(uint32 u)
{
return u < INT_STATIC_LIMIT;
}
inline JSStaticAtom &
JSAtom::uintStatic(uint32 u)
inline JSAtom *
js::StaticStrings::getUint(uint32 u)
{
JS_ASSERT(hasUintStatic(u));
return *reinterpret_cast<JSStaticAtom *>(const_cast<JSString::Data *>(intStaticTable[u]));
JS_ASSERT(hasUint(u));
return intStaticTable[u];
}
inline bool
JSAtom::hasIntStatic(int32 i)
js::StaticStrings::hasInt(int32 i)
{
return uint32(i) < INT_STATIC_LIMIT;
}
inline JSStaticAtom &
JSAtom::intStatic(jsint i)
inline JSAtom *
js::StaticStrings::getInt(jsint i)
{
JS_ASSERT(hasIntStatic(i));
return uintStatic(uint32(i));
JS_ASSERT(hasInt(i));
return getUint(uint32(i));
}
inline JSLinearString *
JSAtom::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
js::StaticStrings::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
{
JS_ASSERT(index < str->length());
const jschar *chars = str->getChars(cx);
@ -248,38 +247,38 @@ JSAtom::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
return NULL;
jschar c = chars[index];
if (c < UNIT_STATIC_LIMIT)
return &unitStatic(c);
return getUnit(c);
return js_NewDependentString(cx, str, index, 1);
}
inline JSStaticAtom &
JSAtom::length2Static(jschar c1, jschar c2)
inline JSAtom *
js::StaticStrings::getLength2(jschar c1, jschar c2)
{
JS_ASSERT(fitsInSmallChar(c1));
JS_ASSERT(fitsInSmallChar(c2));
size_t index = (((size_t)toSmallChar[c1]) << 6) + toSmallChar[c2];
return (JSStaticAtom &)length2StaticTable[index];
return length2StaticTable[index];
}
inline JSStaticAtom &
JSAtom::length2Static(uint32 i)
inline JSAtom *
js::StaticStrings::getLength2(uint32 i)
{
JS_ASSERT(i < 100);
return length2Static('0' + i / 10, '0' + i % 10);
return getLength2('0' + i / 10, '0' + i % 10);
}
/* Get a static atomized string for chars if possible. */
inline JSStaticAtom *
JSAtom::lookupStatic(const jschar *chars, size_t length)
inline JSAtom *
js::StaticStrings::lookup(const jschar *chars, size_t length)
{
switch (length) {
case 1:
if (chars[0] < UNIT_STATIC_LIMIT)
return &unitStatic(chars[0]);
return getUnit(chars[0]);
return NULL;
case 2:
if (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]))
return &length2Static(chars[0], chars[1]);
return getLength2(chars[0], chars[1]);
return NULL;
case 3:
/*
@ -297,7 +296,7 @@ JSAtom::lookupStatic(const jschar *chars, size_t length)
(chars[2] - '0');
if (jsuint(i) < INT_STATIC_LIMIT)
return &intStatic(i);
return getInt(i);
}
return NULL;
}
@ -305,87 +304,11 @@ JSAtom::lookupStatic(const jschar *chars, size_t length)
return NULL;
}
#else /* defined(JS_HAS_STATIC_STRINGS) */
inline bool
JSAtom::fitsInSmallChar(jschar c)
{
return false;
}
inline bool
JSAtom::hasUnitStatic(jschar c)
{
return false;
}
inline JSStaticAtom &
JSAtom::unitStatic(jschar c)
{
JS_NOT_REACHED("no static strings");
return *(JSStaticAtom *)NULL;
}
inline bool
JSAtom::hasUintStatic(uint32 u)
{
return false;
}
inline JSStaticAtom &
JSAtom::uintStatic(uint32 u)
{
JS_NOT_REACHED("no static strings");
return *(JSStaticAtom *)NULL;
}
inline bool
JSAtom::hasIntStatic(int32 i)
{
return false;
}
inline JSStaticAtom &
JSAtom::intStatic(jsint i)
{
JS_NOT_REACHED("no static strings");
return *(JSStaticAtom *)NULL;
}
inline JSLinearString *
JSAtom::getUnitStringForElement(JSContext *cx, JSString *str, size_t index)
{
JS_ASSERT(index < str->length());
return js_NewDependentString(cx, str, index, 1);
}
inline JSStaticAtom &
JSAtom::length2Static(jschar c1, jschar c2)
{
JS_NOT_REACHED("no static strings");
return *(JSStaticAtom *)NULL;
}
inline JSStaticAtom &
JSAtom::length2Static(uint32 i)
{
JS_NOT_REACHED("no static strings");
return *(JSStaticAtom *)NULL;
}
/* Get a static atomized string for chars if possible. */
inline JSStaticAtom *
JSAtom::lookupStatic(const jschar *chars, size_t length)
{
return NULL;
}
#endif /* defined(JS_HAS_STATIC_STRINGS) */
JS_ALWAYS_INLINE void
JSString::finalize(JSContext *cx)
{
/* Statics are not GC-things and shorts are in a different arena. */
JS_ASSERT(!isStaticAtom() && !isShort());
/* Shorts are in a different arena. */
JS_ASSERT(!isShort());
if (isFlat())
asFlat().finalize(cx->runtime);

View File

@ -40,6 +40,8 @@
#include "mozilla/RangedPtr.h"
#include "jsgcmark.h"
#include "String.h"
#include "String-inl.h"
@ -78,7 +80,7 @@ void
JSLinearString::mark(JSTracer *)
{
JSLinearString *str = this;
while (!str->isStaticAtom() && str->markIfUnmarked() && str->isDependent())
while (str->markIfUnmarked() && str->isDependent())
str = str->asDependent().base();
}
@ -114,10 +116,6 @@ JSString::charsHeapSize(JSUsableSizeFun usf)
if (isInline())
return 0;
/* JSStaticAtom: the chars are static and so not part of the heap. */
if (isStaticAtom())
return 0;
/* JSAtom, JSFixedString: count the chars. */
JSFixedString &fixed = asFixed();
size_t usable = usf((void *)fixed.chars());
@ -374,3 +372,120 @@ JSFlatString::isElement(uint32 *indexp) const
return false;
}
/*
* Set up some tools to make it easier to generate large tables. After constant
* folding, for each n, Rn(0) is the comma-separated list R(0), R(1), ..., R(2^n-1).
* Similary, Rn(k) (for any k and n) generates the list R(k), R(k+1), ..., R(k+2^n-1).
* To use this, define R appropriately, then use Rn(0) (for some value of n), then
* undefine R.
*/
#define R2(n) R(n), R((n) + (1 << 0)), R((n) + (2 << 0)), R((n) + (3 << 0))
#define R4(n) R2(n), R2((n) + (1 << 2)), R2((n) + (2 << 2)), R2((n) + (3 << 2))
#define R6(n) R4(n), R4((n) + (1 << 4)), R4((n) + (2 << 4)), R4((n) + (3 << 4))
#define R7(n) R6(n), R6((n) + (1 << 6))
/*
* This is used when we generate our table of short strings, so the compiler is
* happier if we use |c| as few times as possible.
*/
#define FROM_SMALL_CHAR(c) ((c) + ((c) < 10 ? '0' : \
(c) < 36 ? 'a' - 10 : \
'A' - 36))
/*
* Declare length-2 strings. We only store strings where both characters are
* alphanumeric. The lower 10 short chars are the numerals, the next 26 are
* the lowercase letters, and the next 26 are the uppercase letters.
*/
#define TO_SMALL_CHAR(c) ((c) >= '0' && (c) <= '9' ? (c) - '0' : \
(c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 10 : \
(c) >= 'A' && (c) <= 'Z' ? (c) - 'A' + 36 : \
StaticStrings::INVALID_SMALL_CHAR)
#define R TO_SMALL_CHAR
const StaticStrings::SmallChar StaticStrings::toSmallChar[] = { R7(0) };
#undef R
bool
StaticStrings::init(JSContext *cx)
{
SwitchToCompartment sc(cx, cx->runtime->atomsCompartment);
for (uint32 i = 0; i < UNIT_STATIC_LIMIT; i++) {
jschar buffer[] = { i, 0x00 };
JSFixedString *s = js_NewStringCopyN(cx, buffer, 1);
if (!s)
return false;
unitStaticTable[i] = s->morphAtomizedStringIntoAtom();
}
for (uint32 i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++) {
jschar buffer[] = { FROM_SMALL_CHAR(i >> 6), FROM_SMALL_CHAR(i & 0x3F), 0x00 };
JSFixedString *s = js_NewStringCopyN(cx, buffer, 2);
if (!s)
return false;
length2StaticTable[i] = s->morphAtomizedStringIntoAtom();
}
for (uint32 i = 0; i < INT_STATIC_LIMIT; i++) {
if (i < 10) {
intStaticTable[i] = unitStaticTable[i + '0'];
} else if (i < 100) {
size_t index = ((size_t)TO_SMALL_CHAR((i / 10) + '0') << 6) +
TO_SMALL_CHAR((i % 10) + '0');
intStaticTable[i] = length2StaticTable[index];
} else {
jschar buffer[] = { (i / 100) + '0', ((i / 10) % 10) + '0', (i % 10) + '0', 0x00 };
JSFixedString *s = js_NewStringCopyN(cx, buffer, 3);
if (!s)
return false;
intStaticTable[i] = s->morphAtomizedStringIntoAtom();
}
}
initialized = true;
return true;
}
void
StaticStrings::trace(JSTracer *trc)
{
if (!initialized)
return;
for (uint32 i = 0; i < UNIT_STATIC_LIMIT; i++)
MarkString(trc, unitStaticTable[i], "unit-static-string");
for (uint32 i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++)
MarkString(trc, length2StaticTable[i], "length2-static-string");
/* This may mark some strings more than once, but so be it. */
for (uint32 i = 0; i < INT_STATIC_LIMIT; i++)
MarkString(trc, intStaticTable[i], "int-static-string");
}
bool
StaticStrings::isStatic(JSAtom *atom)
{
const jschar *chars = atom->chars();
switch (atom->length()) {
case 1:
return (chars[0] < UNIT_STATIC_LIMIT);
case 2:
return (fitsInSmallChar(chars[0]) && fitsInSmallChar(chars[1]));
case 3:
if ('1' <= chars[0] && chars[0] <= '9' &&
'0' <= chars[1] && chars[1] <= '9' &&
'0' <= chars[2] && chars[2] <= '9') {
jsint i = (chars[0] - '0') * 100 +
(chars[1] - '0') * 10 +
(chars[2] - '0');
return (jsuint(i) < INT_STATIC_LIMIT);
}
return false;
default:
return false;
}
}

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
@ -49,12 +49,12 @@ class JSExtensibleString;
class JSExternalString;
class JSLinearString;
class JSFixedString;
class JSStaticAtom;
class JSRope;
class JSAtom;
namespace js {
class StaticStrings;
class PropertyName;
/* The buffer length required to contain any unsigned 32-bit integer. */
@ -114,11 +114,6 @@ js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNot
* canonicalized to "atoms" (JSAtom) such that there is a single atom with a
* given (length,chars).
*
* - To avoid dynamic creation of common short strings (e.g., single-letter
* alphanumeric strings, numeric strings up to 999) headers and char arrays
* for such strings are allocated in static memory (JSStaticAtom) and used
* as atoms.
*
* - To avoid copying all strings created through the JSAPI, an "external"
* string (JSExternalString) can be created whose chars are managed by the
* JSAPI client.
@ -150,12 +145,10 @@ js_AtomizeString(JSContext *cx, JSString *str, js::InternBehavior ib = js::DoNot
* | | JSShortString - / header is fat
* | | |
* JSAtom | | - / string equality === pointer equality
* | \ | |
* | JSInlineAtom | - / atomized JSInlineString
* | \ |
* | JSShortAtom - / atomized JSShortString
* |
* JSStaticAtom - / header and chars statically allocated
* \ | |
* JSInlineAtom | - / atomized JSInlineString
* \ |
* JSShortAtom - / atomized JSShortString
*
* Classes marked with (abstract) above are not literally C++ Abstract Base
* Classes (since there are no virtual functions, pure or not, in this
@ -258,9 +251,6 @@ class JSString : public js::gc::Cell
static const size_t ATOM_MASK = JS_BITMASK(3);
static const size_t ATOM_FLAGS = 0x0;
static const size_t STATIC_ATOM_MASK = JS_BITMASK(4);
static const size_t STATIC_ATOM_FLAGS = 0x0;
static const size_t EXTENSIBLE_FLAGS = JS_BIT(2) | JS_BIT(3);
static const size_t NON_STATIC_ATOM = JS_BIT(3);
@ -400,11 +390,6 @@ class JSString : public js::gc::Cell
return *(JSAtom *)this;
}
JS_ALWAYS_INLINE
bool isStaticAtom() const {
return (d.lengthAndFlags & FLAGS_MASK) == STATIC_ATOM_FLAGS;
}
/* Only called by the GC for strings with the FINALIZE_STRING kind. */
inline void finalize(JSContext *cx);
@ -655,79 +640,9 @@ class JSExternalString : public JSFixedString
JS_STATIC_ASSERT(sizeof(JSExternalString) == sizeof(JSString));
#if !defined(__ia64__)
/*
* Don't use static strings on ia64 since the compiler may put the static
* memory out of the acceptable 47-bit jsval pointer range.
*/
# define JS_HAS_STATIC_STRINGS
#endif
class JSAtom : public JSFixedString
{
public:
/* Exposed only for jits. */
#ifdef JS_HAS_STATIC_STRINGS
static const size_t UNIT_STATIC_LIMIT = 256U;
static const size_t SMALL_CHAR_LIMIT = 128U; /* Bigger chars cannot be in a length-2 string. */
static const size_t NUM_SMALL_CHARS = 64U;
static const size_t INT_STATIC_LIMIT = 256U;
static const size_t NUM_HUNDRED_STATICS = 156U;
# ifdef __SUNPRO_CC
# pragma align 8 (__1cGJSAtomPunitStaticTable_, __1cGJSAtomSlength2StaticTable_, __1cGJSAtomShundredStaticTable_)
# endif
static const JSString::Data unitStaticTable[];
static const JSString::Data length2StaticTable[];
static const JSString::Data hundredStaticTable[];
static const JSString::Data *const intStaticTable[];
#endif
private:
/* Defined in jsgcinlines.h */
static inline bool isUnitString(const void *ptr);
static inline bool isLength2String(const void *ptr);
static inline bool isHundredString(const void *ptr);
typedef uint8 SmallChar;
static const SmallChar INVALID_SMALL_CHAR = -1;
static inline bool fitsInSmallChar(jschar c);
static const jschar fromSmallChar[];
static const SmallChar toSmallChar[];
static void staticAsserts() {
JS_STATIC_ASSERT(sizeof(JSString::Data) == sizeof(JSString));
}
static JSStaticAtom &length2Static(jschar c1, jschar c2);
static JSStaticAtom &length2Static(uint32 i);
public:
/*
* While this query can be used for any pointer to GC thing, given a
* JSString 'str', it is more efficient to use 'str->isStaticAtom()'.
*/
static inline bool isStatic(const void *ptr);
static inline bool hasUintStatic(uint32 u);
static inline JSStaticAtom &uintStatic(uint32 u);
static inline bool hasIntStatic(int32 i);
static inline JSStaticAtom &intStatic(jsint i);
static inline bool hasUnitStatic(jschar c);
static JSStaticAtom &unitStatic(jschar c);
/* May not return atom, returns null on (reported) failure. */
static inline JSLinearString *getUnitStringForElement(JSContext *cx, JSString *str, size_t index);
/* Return null if no static atom exists for the given (chars, length). */
static inline JSStaticAtom *lookupStatic(const jschar *chars, size_t length);
/* Returns the PropertyName for this. isElement() must be false. */
inline js::PropertyName *asPropertyName();
@ -756,13 +671,61 @@ class JSShortAtom : public JSShortString /*, JSInlineAtom */
JS_STATIC_ASSERT(sizeof(JSShortAtom) == sizeof(JSShortString));
class JSStaticAtom : public JSAtom
{};
JS_STATIC_ASSERT(sizeof(JSStaticAtom) == sizeof(JSString));
namespace js {
class StaticStrings
{
private:
bool initialized;
/* Bigger chars cannot be in a length-2 string. */
static const size_t SMALL_CHAR_LIMIT = 128U;
static const size_t NUM_SMALL_CHARS = 64U;
static const size_t INT_STATIC_LIMIT = 256U;
JSAtom *length2StaticTable[NUM_SMALL_CHARS * NUM_SMALL_CHARS];
JSAtom *intStaticTable[INT_STATIC_LIMIT];
public:
/* We keep these public for the methodjit. */
static const size_t UNIT_STATIC_LIMIT = 256U;
JSAtom *unitStaticTable[UNIT_STATIC_LIMIT];
StaticStrings() : initialized(false) {}
bool init(JSContext *cx);
void trace(JSTracer *trc);
static inline bool hasUint(uint32 u);
inline JSAtom *getUint(uint32 u);
static inline bool hasInt(int32 i);
inline JSAtom *getInt(jsint i);
static inline bool hasUnit(jschar c);
JSAtom *getUnit(jschar c);
/* May not return atom, returns null on (reported) failure. */
inline JSLinearString *getUnitStringForElement(JSContext *cx, JSString *str, size_t index);
static bool isStatic(JSAtom *atom);
/* Return null if no static atom exists for the given (chars, length). */
inline JSAtom *lookup(const jschar *chars, size_t length);
private:
typedef uint8 SmallChar;
static const SmallChar INVALID_SMALL_CHAR = -1;
static inline bool fitsInSmallChar(jschar c);
static const SmallChar toSmallChar[];
JSAtom *getLength2(jschar c1, jschar c2);
JSAtom *getLength2(uint32 i);
};
/*
* Represents an atomized string which does not contain an unsigned 32-bit
* value. That is, it is never the case that for a PropertyName propname,

View File

@ -3883,6 +3883,31 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState,
return NS_OK;
}
static void
SetFlagsOnSubtree(nsIContent *aNode, PtrBits aFlagsToSet)
{
#ifdef DEBUG
// Make sure that the node passed to us doesn't have any XBL children
{
nsIDocument *doc = aNode->GetOwnerDoc();
NS_ASSERTION(doc, "The node must be in a document");
NS_ASSERTION(!doc->BindingManager()->GetXBLChildNodesFor(aNode),
"The node should not have any XBL children");
}
#endif
// Set the flag on the node itself
aNode->SetFlags(aFlagsToSet);
// Set the flag on all of its children recursively
PRUint32 count;
nsIContent * const *children = aNode->GetChildArray(&count);
for (PRUint32 index = 0; index < count; ++index) {
SetFlagsOnSubtree(children[index], aFlagsToSet);
}
}
nsresult
nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
nsIFrame* aParentFrame,
@ -3910,7 +3935,17 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent,
content->SetNativeAnonymous();
}
PRBool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE);
rv = content->BindToTree(mDocument, aParent, aParent, PR_TRUE);
// If the anonymous content creator requested that the content should be
// editable, honor its request.
// We need to set the flag on the whole subtree, because existing
// children's flags have already been set as part of the BindToTree operation.
if (anonContentIsEditable) {
NS_ASSERTION(aParentFrame->GetType() == nsGkAtoms::textInputFrame,
"We only expect this for anonymous content under a text control frame");
SetFlagsOnSubtree(content, NODE_IS_EDITABLE);
}
if (NS_FAILED(rv)) {
content->UnbindFromTree();
return rv;
@ -6137,25 +6172,6 @@ nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent,
ContentInserted(aParentContent, aContent, nsnull, PR_FALSE);
}
// We want to disable lazy frame construction for nodes that are under an
// editor. We use nsINode::IsEditable, but that includes inputs with type text
// and password and textareas, which are common and aren't really editable (the
// native anonymous content under them is what is actually editable) so we want
// to construct frames for those lazily.
// The logic for this check is based on
// nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept
// in sync with that. MayHaveContentEditableAttr() being true only indicates
// a contenteditable attribute, it doesn't indicate whether it is true or false,
// so we force eager construction in some cases when the node is not editable,
// but that should be rare.
static inline PRBool
IsActuallyEditable(nsIContent* aContainer, nsIContent* aChild)
{
return (aChild->IsEditable() &&
(aContainer->IsEditable() ||
aChild->MayHaveContentEditableAttr()));
}
// For inserts aChild should be valid, for appends it should be null.
// Returns true if this operation can be lazy, false if not.
PRBool
@ -6170,7 +6186,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
if (aOperation == CONTENTINSERT) {
if (aChild->IsRootOfAnonymousSubtree() ||
aChild->IsXUL() || IsActuallyEditable(aContainer, aChild)) {
aChild->IsEditable() || aChild->IsXUL()) {
return PR_FALSE;
}
} else { // CONTENTAPPEND
@ -6179,7 +6195,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation,
for (nsIContent* child = aChild; child; child = child->GetNextSibling()) {
NS_ASSERTION(!child->IsRootOfAnonymousSubtree(),
"Should be coming through the CONTENTAPPEND case");
if (child->IsXUL() || IsActuallyEditable(aContainer, child)) {
if (child->IsXUL() || child->IsEditable()) {
return PR_FALSE;
}
}
@ -7961,6 +7977,12 @@ nsCSSFrameConstructor::ProcessRestyledFrames(nsStyleChangeList& aChangeList)
}
if (hint & nsChangeHint_ReconstructFrame) {
// If we ever start passing PR_TRUE here, be careful of restyles
// that involve a reframe and animations. In particular, if the
// restyle we're processing here is an animation restyle, but
// the style resolution we will do for the frame construction
// happens async when we're not in an animation restyle already,
// problems could arise.
RecreateFramesForContent(content, PR_FALSE);
} else {
NS_ASSERTION(frame, "This shouldn't happen");

View File

@ -4050,27 +4050,10 @@ nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement,
return result;
}
// In case of data: URIs, we want to ignore principals;
// they should have the originating content's principal,
// but that's broken at the moment in imgLib.
nsCOMPtr<nsIURI> uri;
rv = imgRequest->GetURI(getter_AddRefs(uri));
if (NS_FAILED(rv))
return result;
PRBool isDataURI = PR_FALSE;
rv = uri->SchemeIs("data", &isDataURI);
if (NS_FAILED(rv))
return result;
// Data URIs are always OK; set the principal
// to null to indicate that.
nsCOMPtr<nsIPrincipal> principal;
if (!isDataURI) {
rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
if (NS_FAILED(rv) || !principal)
return result;
}
rv = imgRequest->GetImagePrincipal(getter_AddRefs(principal));
if (NS_FAILED(rv) || !principal)
return result;
nsCOMPtr<imgIContainer> imgContainer;
rv = imgRequest->GetImage(getter_AddRefs(imgContainer));

View File

@ -1357,7 +1357,8 @@ public:
nsRefPtr<gfxASurface> mSurface;
/* The size of the surface */
gfxIntSize mSize;
/* The principal associated with the element whose surface was returned */
/* The principal associated with the element whose surface was returned.
If there is a surface, this will never be null. */
nsCOMPtr<nsIPrincipal> mPrincipal;
/* The image request, if the element is an nsIImageLoadingContent */
nsCOMPtr<imgIRequest> mImageRequest;

View File

@ -79,6 +79,10 @@ public:
* Creates "native" anonymous content and adds the created content to
* the aElements array. None of the returned elements can be nsnull.
*
* If the anonymous content creator sets the editable flag on some
* of the elements that it creates, the flag will be applied to the node
* upon being bound to the document.
*
* @note The returned elements are owned by this object. This object is
* responsible for calling UnbindFromTree on the elements it returned
* from CreateAnonymousContent when appropriate (i.e. before releasing

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<input>
<input readonly>
<input type=password>
<input type=password readonly>
<input type=email>
<input type=email readonly>
<textarea></textarea>
<textarea readonly></textarea>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
:-moz-read-write + span {
display: none;
}
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body contenteditable>
<input><span>hide me</span>
<input readonly><span>hide me</span>
<input type=password><span>hide me</span>
<input type=password readonly><span>hide me</span>
<input type=email><span>hide me</span>
<input type=email readonly><span>hide me</span>
<textarea></textarea><span>hide me</span>
<textarea readonly></textarea><span>hide me</span>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<style>
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body>
<input><span>hide me</span>
<input readonly>
<input type=password><span>hide me</span>
<input type=password readonly>
<input type=email><span>hide me</span>
<input type=email readonly>
<textarea></textarea><span>hide me</span>
<textarea readonly></textarea>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
:-moz-read-only + span {
display: none;
}
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body>
<input><span>hide me</span>
<input readonly><span>hide me</span>
<input type=password><span>hide me</span>
<input type=password readonly><span>hide me</span>
<input type=email><span>hide me</span>
<input type=email readonly><span>hide me</span>
<textarea></textarea><span>hide me</span>
<textarea readonly></textarea><span>hide me</span>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<body>
<input>
<input readonly>
<input type=password>
<input type=password readonly>
<input type=email>
<input type=email readonly>
<textarea></textarea>
<textarea readonly></textarea>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
:-moz-read-write + span {
display: none;
}
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body contenteditable>
<input><span>hide me</span>
<input readonly><span>hide me</span>
<input type=password><span>hide me</span>
<input type=password readonly><span>hide me</span>
<input type=email><span>hide me</span>
<input type=email readonly><span>hide me</span>
<textarea></textarea><span>hide me</span>
<textarea readonly></textarea><span>hide me</span>
</body>
</html>

View File

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<style>
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body>
<input>
<input readonly><span>hide me</span>
<input type=password>
<input type=password readonly><span>hide me</span>
<input type=email>
<input type=email readonly><span>hide me</span>
<textarea></textarea>
<textarea readonly></textarea><span>hide me</span>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
:-moz-read-write + span {
display: none;
}
span {
color: transparent; /* workaround for bug 617524 */
outline: 1px solid green;
}
</style>
</head>
<body>
<input><span>hide me</span>
<input readonly><span>hide me</span>
<input type=password><span>hide me</span>
<input type=password readonly><span>hide me</span>
<input type=email><span>hide me</span>
<input type=email readonly><span>hide me</span>
<textarea></textarea><span>hide me</span>
<textarea readonly></textarea><span>hide me</span>
</body>
</html>

View File

@ -69,4 +69,8 @@ skip-if(Android) == 674212-spellcheck.html 674212-spellcheck-ref.html
skip-if(Android) == 338427-2.html 338427-2-ref.html
skip-if(Android) == 338427-3.html 338427-3-ref.html
skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.html
== readwrite-non-editable.html readwrite-non-editable-ref.html
== readwrite-editable.html readwrite-editable-ref.html
== readonly-non-editable.html readonly-non-editable-ref.html
== readonly-editable.html readonly-editable-ref.html
== dynamic-overflow-change.html dynamic-overflow-change-ref.html

View File

@ -1362,17 +1362,19 @@ nsStyleSet::GCRuleTrees()
}
static inline nsRuleNode*
SkipTransitionRules(nsRuleNode* aRuleNode, Element* aElement, PRBool isPseudo)
SkipAnimationRules(nsRuleNode* aRuleNode, Element* aElement, PRBool isPseudo)
{
nsRuleNode* ruleNode = aRuleNode;
while (!ruleNode->IsRoot() &&
ruleNode->GetLevel() == nsStyleSet::eTransitionSheet) {
(ruleNode->GetLevel() == nsStyleSet::eTransitionSheet ||
ruleNode->GetLevel() == nsStyleSet::eAnimationSheet)) {
ruleNode = ruleNode->GetParent();
}
if (ruleNode != aRuleNode) {
NS_ASSERTION(aElement, "How can we have transition rules but no element?");
// Need to do an animation restyle, just like
// nsTransitionManager::WalkTransitionRule would.
// nsTransitionManager::WalkTransitionRule and
// nsAnimationManager::GetAnimationRule would.
nsRestyleHint hint = isPseudo ? eRestyle_Subtree : eRestyle_Self;
aRuleNode->GetPresContext()->PresShell()->RestyleForAnimation(aElement,
hint);
@ -1403,16 +1405,16 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
// Skip transition rules as needed just like
// nsTransitionManager::WalkTransitionRule would.
PRBool skipTransitionRules = PresContext()->IsProcessingRestyles() &&
PRBool skipAnimationRules = PresContext()->IsProcessingRestyles() &&
!PresContext()->IsProcessingAnimationStyleChange();
if (skipTransitionRules) {
// FIXME do something here for animations?
// Make sure that we're not using transition rules for our new style
// context. If we need them, an animation restyle will provide.
if (skipAnimationRules) {
// Make sure that we're not using transition rules or animation rules for
// our new style context. If we need them, an animation restyle will
// provide.
ruleNode =
SkipTransitionRules(ruleNode, aElement,
pseudoType !=
nsCSSPseudoElements::ePseudo_NotPseudoElement);
SkipAnimationRules(ruleNode, aElement,
pseudoType !=
nsCSSPseudoElements::ePseudo_NotPseudoElement);
}
nsRuleNode* visitedRuleNode = nsnull;
@ -1424,12 +1426,12 @@ nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
if (visitedContext) {
visitedRuleNode = visitedContext->GetRuleNode();
// Again, skip transition rules as needed
if (skipTransitionRules) {
if (skipAnimationRules) {
// FIXME do something here for animations?
visitedRuleNode =
SkipTransitionRules(visitedRuleNode, aElement,
pseudoType !=
nsCSSPseudoElements::ePseudo_NotPseudoElement);
SkipAnimationRules(visitedRuleNode, aElement,
pseudoType !=
nsCSSPseudoElements::ePseudo_NotPseudoElement);
}
}

View File

@ -1219,6 +1219,39 @@ is(cs.marginTop, "40px",
"rest of animation should still work when UA !important present at 200ms");
done_div();
// Test interaction of animations and restyling (Bug 686656).
// This test depends on kf3 getting its 0% and 100% values from the
// rules below it in the cascade; we're checking that the animation
// isn't rebuilt when the restyles happen.
new_div("-moz-animation: kf3 1s linear forwards");
is(cs.marginTop, "0px", "bug 686656 test 1 at 0ms");
advance_clock(250);
display.style.color = "blue";
is(cs.marginTop, "100px", "bug 686656 test 1 at 250ms");
advance_clock(375);
is(cs.marginTop, "50px", "bug 686656 test 1 at 625ms");
advance_clock(375);
is(cs.marginTop, "0px", "bug 686656 test 1 at 1000ms");
done_div();
display.style.color = "";
// Test interaction of animations and restyling (Bug 686656),
// with reframing.
// This test depends on kf3 getting its 0% and 100% values from the
// rules below it in the cascade; we're checking that the animation
// isn't rebuilt when the restyles happen.
new_div("-moz-animation: kf3 1s linear forwards");
is(cs.marginTop, "0px", "bug 686656 test 2 at 0ms");
advance_clock(250);
display.style.overflow = "scroll";
is(cs.marginTop, "100px", "bug 686656 test 2 at 250ms");
advance_clock(375);
is(cs.marginTop, "50px", "bug 686656 test 2 at 625ms");
advance_clock(375);
is(cs.marginTop, "0px", "bug 686656 test 2 at 1000ms");
done_div();
display.style.overflow = "";
SpecialPowers.DOMWindowUtils.restoreNormalRefresh();
</script>

View File

@ -0,0 +1,122 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Wes Johnston <wjohnston@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var CharsetMenu = {
_strings: null,
_charsets: null,
get strings() {
if (!this._strings)
this._strings = Services.strings.createBundle("chrome://global/locale/charsetTitles.properties");
return this._strings;
},
init: function() {
PageActions.register("pageaction-charset", this.updatePageAction, this);
},
updatePageAction: function(aNode) {
let pref = Services.prefs.getComplexValue("browser.menu.showCharacterEncoding", Ci.nsIPrefLocalizedString).data;
if (pref == "true") {
let charset = getBrowser().documentCharsetInfo.forcedCharset;
if (charset) {
charset = charset.toString();
charset = charset.trim().toLowerCase();
aNode.setAttribute("description", this.strings.GetStringFromName(charset + ".title"));
} else if (aNode.hasAttribute("description")) {
aNode.removeAttribute("description");
}
}
return ("true" == pref)
},
_toMenuItems: function(aCharsets, aCurrent) {
let ret = [];
aCharsets.forEach(function (aSet) {
try {
let string = aSet.trim().toLowerCase();
ret.push({
label: this.strings.GetStringFromName(string + ".title"),
value: string,
selected: (string == aCurrent)
});
} catch(ex) { }
}, this);
return ret;
},
menu : {
dispatchEvent: function(aEvent) {
if (aEvent.type == "command")
CharsetMenu.setCharset(this.menupopup.children[this.selectedIndex].value);
},
menupopup: {
hasAttribute: function(aAttr) { return false; },
},
selectedIndex: -1
},
get charsets() {
if (!this._charsets) {
this._charsets = Services.prefs.getComplexValue("intl.charsetmenu.browser.static", Ci.nsIPrefLocalizedString).data.split(",");
}
let charsets = this._charsets;
let currentCharset = getBrowser().documentCharsetInfo.forcedCharset;
if (currentCharset) {
currentCharset = currentCharset.toString();
currentCharset = currentCharset.trim().toLowerCase();
if (charsets.indexOf(currentCharset) == -1)
charsets.splice(0, 0, currentCharset);
}
return this._toMenuItems(charsets, currentCharset);
},
show: function showCharsetMenu() {
this.menu.menupopup.children = this.charsets;
MenuListHelperUI.show(this.menu);
},
setCharset: function setCharset(aCharset) {
let browser = getBrowser();
browser.messageManager.sendAsyncMessage("Browser:SetCharset", {
charset: aCharset
});
let history = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
history.setCharsetForURI(browser.documentURI, aCharset);
}
};

View File

@ -0,0 +1,273 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Brubeck <mbrubeck@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var PageActions = {
_handlers: null,
init: function init() {
if (this._handlers)
return;
this._handlers = [];
document.getElementById("pageactions-container").addEventListener("click", this, true);
this.register("pageaction-reset", this.updatePagePermissions, this);
this.register("pageaction-password", this.updateForgetPassword, this);
#ifdef NS_PRINTING
this.register("pageaction-saveas", this.updatePageSaveAs, this);
#endif
this.register("pageaction-share", this.updateShare, this);
this.register("pageaction-search", BrowserSearch.updatePageSearchEngines, BrowserSearch);
this.register("pageaction-webapps-install", WebappsUI.updateWebappsInstall, WebappsUI);
CharsetMenu.init();
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "click":
getIdentityHandler().hide();
break;
}
},
/**
* @param aId id of a pageaction element
* @param aCallback function that takes an element and returns true if it should be visible
* @param aThisObj (optional) scope object for aCallback
*/
register: function register(aId, aCallback, aThisObj) {
this._handlers.push({id: aId, callback: aCallback, obj: aThisObj});
},
updateSiteMenu: function updateSiteMenu() {
this.init();
this._handlers.forEach(function(action) {
let node = document.getElementById(action.id);
if (node)
node.hidden = !action.callback.call(action.obj, node);
});
this._updateAttributes();
},
get _loginManager() {
delete this._loginManager;
return this._loginManager = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
},
// Permissions we track in Page Actions
_permissions: ["popup", "offline-app", "geolocation", "desktop-notification"],
_forEachPermissions: function _forEachPermissions(aHost, aCallback) {
let pm = Services.perms;
for (let i = 0; i < this._permissions.length; i++) {
let type = this._permissions[i];
if (!pm.testPermission(aHost, type))
continue;
let perms = pm.enumerator;
while (perms.hasMoreElements()) {
let permission = perms.getNext().QueryInterface(Ci.nsIPermission);
if (permission.host == aHost.asciiHost && permission.type == type)
aCallback(type);
}
}
},
updatePagePermissions: function updatePagePermissions(aNode) {
let host = Browser.selectedBrowser.currentURI;
let permissions = [];
this._forEachPermissions(host, function(aType) {
permissions.push("pageactions." + aType);
});
if (!this._loginManager.getLoginSavingEnabled(host.prePath)) {
// If rememberSignons is false, then getLoginSavingEnabled returns false
// for all pages, so we should just ignore it (Bug 601163).
if (Services.prefs.getBoolPref("signon.rememberSignons"))
permissions.push("pageactions.password");
}
let descriptions = permissions.map(function(s) Strings.browser.GetStringFromName(s));
aNode.setAttribute("description", descriptions.join(", "));
return (permissions.length > 0);
},
updateForgetPassword: function updateForgetPassword(aNode) {
let host = Browser.selectedBrowser.currentURI;
let logins = this._loginManager.findLogins({}, host.prePath, "", "");
return logins.some(function(login) login.hostname == host.prePath);
},
forgetPassword: function forgetPassword(aEvent) {
let host = Browser.selectedBrowser.currentURI;
let lm = this._loginManager;
lm.findLogins({}, host.prePath, "", "").forEach(function(login) {
if (login.hostname == host.prePath)
lm.removeLogin(login);
});
this.hideItem(aEvent.target);
aEvent.stopPropagation(); // Don't hide the site menu.
},
clearPagePermissions: function clearPagePermissions(aEvent) {
let pm = Services.perms;
let host = Browser.selectedBrowser.currentURI;
this._forEachPermissions(host, function(aType) {
pm.remove(host.asciiHost, aType);
// reset the 'remember' counter for permissions that support it
if (["geolocation", "desktop-notification"].indexOf(aType) != -1)
Services.contentPrefs.setPref(host.asciiHost, aType + ".request.remember", 0);
});
let lm = this._loginManager;
if (!lm.getLoginSavingEnabled(host.prePath))
lm.setLoginSavingEnabled(host.prePath, true);
this.hideItem(aEvent.target);
aEvent.stopPropagation(); // Don't hide the site menu.
},
savePageAsPDF: function saveAsPDF() {
let browser = Browser.selectedBrowser;
let fileName = ContentAreaUtils.getDefaultFileName(browser.contentTitle, browser.documentURI, null, null);
fileName = fileName.trim() + ".pdf";
let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
let downloadsDir = dm.defaultDownloadsDirectory;
#ifdef ANDROID
// Create the final destination file location
let file = downloadsDir.clone();
file.append(fileName);
file.createUnique(file.NORMAL_FILE_TYPE, 0666);
#else
let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
picker.init(window, Strings.browser.GetStringFromName("pageactions.saveas.pdf"), Ci.nsIFilePicker.modeSave);
picker.appendFilter("PDF", "*.pdf");
picker.defaultExtension = "pdf";
picker.defaultString = fileName;
picker.displayDirectory = downloadsDir;
let rv = picker.show();
if (rv == Ci.nsIFilePicker.returnCancel)
return;
let file = picker.file;
#endif
fileName = file.leafName;
// We must manually add this to the download system
let db = dm.DBConnection;
let stmt = db.createStatement(
"INSERT INTO moz_downloads (name, source, target, startTime, endTime, state, referrer) " +
"VALUES (:name, :source, :target, :startTime, :endTime, :state, :referrer)"
);
let current = browser.currentURI.spec;
stmt.params.name = fileName;
stmt.params.source = current;
stmt.params.target = Services.io.newFileURI(file).spec;
stmt.params.startTime = Date.now() * 1000;
stmt.params.endTime = Date.now() * 1000;
stmt.params.state = Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED;
stmt.params.referrer = current;
stmt.execute();
stmt.finalize();
let newItemId = db.lastInsertRowID;
let download = dm.getDownload(newItemId);
try {
DownloadsView.downloadStarted(download);
}
catch(e) {}
Services.obs.notifyObservers(download, "dl-start", null);
#ifdef ANDROID
let tmpDir = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
file = tmpDir.clone();
file.append(fileName);
#endif
let data = {
type: Ci.nsIPrintSettings.kOutputFormatPDF,
id: newItemId,
referrer: current,
filePath: file.path
};
Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:SaveAs", data);
},
updatePageSaveAs: function updatePageSaveAs(aNode) {
// Check for local XUL content
let contentWindow = Browser.selectedBrowser.contentWindow;
return !(contentWindow && contentWindow.document instanceof XULDocument);
},
updateShare: function updateShare(aNode) {
return Util.isShareableScheme(Browser.selectedBrowser.currentURI.scheme);
},
hideItem: function hideItem(aNode) {
aNode.hidden = true;
this._updateAttributes();
},
_updateAttributes: function _updateAttributes() {
let container = document.getElementById("pageactions-container");
let visibleNodes = container.querySelectorAll("pageaction:not([hidden=true])");
let visibleCount = visibleNodes.length;
for (let i = 0; i < visibleCount; i++)
visibleNodes[i].classList.remove("odd-last-child");
visibleNodes[visibleCount - 1].classList.add("last-child");
if (visibleCount % 2)
visibleNodes[visibleCount - 1].classList.add("odd");
}
};

View File

@ -0,0 +1,202 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var SelectionHelper = {
enabled: true,
popupState: null,
target: null,
deltaX: -1,
deltaY: -1,
get _start() {
delete this._start;
return this._start = document.getElementById("selectionhandle-start");
},
get _end() {
delete this._end;
return this._end = document.getElementById("selectionhandle-end");
},
showPopup: function sh_showPopup(aMessage) {
if (!this.enabled || aMessage.json.types.indexOf("content-text") == -1)
return false;
this.popupState = aMessage.json;
this.popupState.target = aMessage.target;
this._start.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._end.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._start.addEventListener("TapUp", this, true);
this._end.addEventListener("TapUp", this, true);
messageManager.addMessageListener("Browser:SelectionRange", this);
messageManager.addMessageListener("Browser:SelectionCopied", this);
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionStart", { x: this.popupState.x, y: this.popupState.y });
// Hide the selection handles
window.addEventListener("TapDown", this, true);
window.addEventListener("resize", this, true);
window.addEventListener("keypress", this, true);
Elements.browsers.addEventListener("URLChanged", this, true);
Elements.browsers.addEventListener("SizeChanged", this, true);
Elements.browsers.addEventListener("ZoomChanged", this, true);
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, false);
this.popupState.target.dispatchEvent(event);
return true;
},
hide: function sh_hide(aEvent) {
if (this._start.hidden)
return;
let pos = this.popupState.target.transformClientToBrowser(aEvent.clientX || 0, aEvent.clientY || 0);
let json = {
x: pos.x,
y: pos.y
};
try {
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionEnd", json);
} catch (e) {
Cu.reportError(e);
}
this.popupState = null;
this._start.hidden = true;
this._end.hidden = true;
this._start.removeEventListener("TapUp", this, true);
this._end.removeEventListener("TapUp", this, true);
messageManager.removeMessageListener("Browser:SelectionRange", this);
window.removeEventListener("TapDown", this, true);
window.removeEventListener("resize", this, true);
window.removeEventListener("keypress", this, true);
Elements.browsers.removeEventListener("URLChanged", this, true);
Elements.browsers.removeEventListener("SizeChanged", this, true);
Elements.browsers.removeEventListener("ZoomChanged", this, true);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "TapDown":
if (aEvent.target == this._start || aEvent.target == this._end) {
this.target = aEvent.target;
this.deltaX = (aEvent.clientX - this.target.left);
this.deltaY = (aEvent.clientY - this.target.top);
window.addEventListener("TapMove", this, true);
} else {
this.hide(aEvent);
}
break;
case "TapUp":
window.removeEventListener("TapMove", this, true);
this.target = null;
this.deltaX = -1;
this.deltaY = -1;
break;
case "TapMove":
if (this.target) {
this.target.left = aEvent.clientX - this.deltaX;
this.target.top = aEvent.clientY - this.deltaY;
let rect = this.target.getBoundingClientRect();
let data = this.target == this._start ? { x: rect.right, y: rect.top, type: "start" } : { x: rect.left, y: rect.top, type: "end" };
let pos = this.popupState.target.transformClientToBrowser(data.x || 0, data.y || 0);
let json = {
type: data.type,
x: pos.x,
y: pos.y
};
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionMove", json);
}
break;
case "resize":
case "SizeChanged":
case "ZoomChanged":
case "URLChanged":
case "keypress":
this.hide(aEvent);
break;
}
},
receiveMessage: function sh_receiveMessage(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "Browser:SelectionRange": {
let pos = this.popupState.target.transformBrowserToClient(json.start.x || 0, json.start.y || 0);
this._start.left = pos.x - 32;
this._start.top = pos.y + this.deltaY;
this._start.hidden = false;
pos = this.popupState.target.transformBrowserToClient(json.end.x || 0, json.end.y || 0);
this._end.left = pos.x;
this._end.top = pos.y;
this._end.hidden = false;
break;
}
case "Browser:SelectionCopied": {
messageManager.removeMessageListener("Browser:SelectionCopied", this);
if (json.succeeded) {
let toaster = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService);
toaster.showAlertNotification(null, Strings.browser.GetStringFromName("selectionHelper.textCopied"), "", false, "", null);
}
break;
}
}
}
};

View File

@ -0,0 +1,173 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabrice Desré <fabrice@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var WebappsUI = {
_dialog: null,
_manifest: null,
_perms: [],
checkBox: function(aEvent) {
let elem = aEvent.originalTarget;
let perm = elem.getAttribute("perm");
if (this._manifest.capabilities && this._manifest.capabilities.indexOf(perm) != -1) {
if (elem.checked) {
elem.classList.remove("webapps-noperm");
elem.classList.add("webapps-perm");
} else {
elem.classList.remove("webapps-perm");
elem.classList.add("webapps-noperm");
}
}
},
show: function show(aManifest) {
if (!aManifest) {
// Try every way to get an icon
let browser = Browser.selectedBrowser;
let icon = browser.appIcon.href;
if (!icon)
icon = browser.mIconURL;
if (!icon)
icon = gFaviconService.getFaviconImageForPage(browser.currentURI).spec;
// Create a simple manifest
aManifest = {
uri: browser.currentURI.spec,
name: browser.contentTitle,
icon: icon,
capabilities: [],
};
}
this._manifest = aManifest;
this._dialog = importDialog(window, "chrome://browser/content/webapps.xul", null);
if (aManifest.name)
document.getElementById("webapps-title").value = aManifest.name;
if (aManifest.icon)
document.getElementById("webapps-icon").src = aManifest.icon;
let uri = Services.io.newURI(aManifest.uri, null, null);
let perms = [["offline", "offline-app"], ["geoloc", "geo"], ["notifications", "desktop-notification"]];
let self = this;
perms.forEach(function(tuple) {
let elem = document.getElementById("webapps-" + tuple[0] + "-checkbox");
let currentPerm = Services.perms.testExactPermission(uri, tuple[1]);
self._perms[tuple[1]] = (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION);
if ((aManifest.capabilities && (aManifest.capabilities.indexOf(tuple[1]) != -1)) || (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION))
elem.checked = true;
else
elem.checked = (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION);
elem.classList.remove("webapps-noperm");
elem.classList.add("webapps-perm");
});
BrowserUI.pushPopup(this, this._dialog);
// Force a modal dialog
this._dialog.waitForClose();
},
hide: function hide() {
this._dialog.close();
this._dialog = null;
BrowserUI.popPopup(this);
},
_updatePermission: function updatePermission(aId, aPerm) {
try {
let uri = Services.io.newURI(this._manifest.uri, null, null);
let currentState = document.getElementById(aId).checked;
if (currentState != this._perms[aPerm])
Services.perms.add(uri, aPerm, currentState ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION);
} catch(e) {
Cu.reportError(e);
}
},
launch: function launch() {
let title = document.getElementById("webapps-title").value;
if (!title)
return;
this._updatePermission("webapps-offline-checkbox", "offline-app");
this._updatePermission("webapps-geoloc-checkbox", "geo");
this._updatePermission("webapps-notifications-checkbox", "desktop-notification");
this.hide();
this.install(this._manifest.uri, title, this._manifest.icon);
},
updateWebappsInstall: function updateWebappsInstall(aNode) {
if (document.getElementById("main-window").hasAttribute("webapp"))
return false;
let browser = Browser.selectedBrowser;
let webapp = Cc["@mozilla.org/webapps/support;1"].getService(Ci.nsIWebappsSupport);
return !(webapp && webapp.isApplicationInstalled(browser.currentURI.spec));
},
install: function(aURI, aTitle, aIcon) {
const kIconSize = 64;
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
canvas.setAttribute("style", "display: none");
let self = this;
let image = new Image();
image.onload = function() {
canvas.width = canvas.height = kIconSize; // clears the canvas
let ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, kIconSize, kIconSize);
let data = canvas.toDataURL("image/png", "");
canvas = null;
try {
let webapp = Cc["@mozilla.org/webapps/support;1"].getService(Ci.nsIWebappsSupport);
webapp.installApplication(aTitle, aURI, aIcon, data);
} catch(e) {
Cu.reportError(e);
}
}
image.onerror = function() {
// can't load the icon (bad URI) : fallback to the default one from chrome
self.install(aURI, aTitle, "chrome://browser/skin/images/favicon-default-30.png");
}
image.src = aIcon;
}
};

View File

@ -69,16 +69,12 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
[
["FullScreenVideo"],
["WebappsUI"],
["BadgeHandlers"],
["ContextHelper"],
["SelectionHelper"],
["FormHelperUI"],
["FindHelperUI"],
["NewTabPopup"],
["PageActions"],
["BrowserSearch"],
["CharsetMenu"]
].forEach(function (aObject) {
XPCOMUtils.defineLazyGetter(window, aObject, function() {
return CommonUI[aObject];
@ -96,6 +92,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
["AwesomeScreen", "chrome://browser/content/AwesomePanel.js"],
["BookmarkHelper", "chrome://browser/content/BookmarkHelper.js"],
["BookmarkPopup", "chrome://browser/content/BookmarkPopup.js"],
["CharsetMenu", "chrome://browser/content/CharsetMenu.js"],
["CommandUpdater", "chrome://browser/content/commandUtil.js"],
["ContextCommands", "chrome://browser/content/ContextCommands.js"],
["ConsoleView", "chrome://browser/content/console.js"],
@ -104,9 +101,11 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
["MenuListHelperUI", "chrome://browser/content/MenuListHelperUI.js"],
["OfflineApps", "chrome://browser/content/OfflineApps.js"],
["IndexedDB", "chrome://browser/content/IndexedDB.js"],
["PageActions", "chrome://browser/content/PageActions.js"],
["PreferencesView", "chrome://browser/content/preferences.js"],
["Sanitizer", "chrome://browser/content/sanitize.js"],
["SelectHelperUI", "chrome://browser/content/SelectHelperUI.js"],
["SelectionHelper", "chrome://browser/content/SelectionHelper.js"],
["ContentPopupHelper", "chrome://browser/content/ContentPopupHelper.js"],
["SharingUI", "chrome://browser/content/SharingUI.js"],
["TabsPopup", "chrome://browser/content/TabsPopup.js"],
@ -114,6 +113,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
#ifdef MOZ_SERVICES_SYNC
["WeaveGlue", "chrome://browser/content/sync.js"],
#endif
["WebappsUI", "chrome://browser/content/WebappsUI.js"],
["SSLExceptions", "chrome://browser/content/exceptions.js"]
].forEach(function (aScript) {
let [name, script] = aScript;

View File

@ -494,10 +494,8 @@ var BrowserUI = {
BadgeHandlers.register(BrowserUI._edit.popup);
FormHelperUI.init();
FindHelperUI.init();
PageActions.init();
FullScreenVideo.init();
NewTabPopup.init();
CharsetMenu.init();
// If some add-ons were disabled during during an application update, alert user
let addonIDs = AddonManager.getStartupChanges("disabled");

View File

@ -586,7 +586,7 @@
<separator flex="1"/>
</scrollbox>
<hbox class="prompt-buttons" pack="center">
<button oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
<button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
</hbox>
</vbox>
<vbox id="syncsetup-fallback" class="syncsetup-page" flex="1" hidden="true">
@ -605,9 +605,9 @@
<separator flex="1"/>
</scrollbox>
<hbox class="prompt-buttons" pack="center">
<button oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
<button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
<separator/>
<button id="syncsetup-button-connect" oncommand="WeaveGlue.close(); WeaveGlue.connect();">&sync.setup.connect;</button>
<button id="syncsetup-button-connect" class="prompt-button" oncommand="WeaveGlue.close(); WeaveGlue.connect();">&sync.setup.connect;</button>
</hbox>
</vbox>
</dialog>

View File

@ -169,236 +169,6 @@ var BrowserSearch = {
}
};
var PageActions = {
init: function init() {
document.getElementById("pageactions-container").addEventListener("click", this, true);
this.register("pageaction-reset", this.updatePagePermissions, this);
this.register("pageaction-password", this.updateForgetPassword, this);
#ifdef NS_PRINTING
this.register("pageaction-saveas", this.updatePageSaveAs, this);
#endif
this.register("pageaction-share", this.updateShare, this);
this.register("pageaction-search", BrowserSearch.updatePageSearchEngines, BrowserSearch);
this.register("pageaction-webapps-install", WebappsUI.updateWebappsInstall, WebappsUI);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "click":
getIdentityHandler().hide();
break;
}
},
/**
* @param aId id of a pageaction element
* @param aCallback function that takes an element and returns true if it should be visible
* @param aThisObj (optional) scope object for aCallback
*/
register: function register(aId, aCallback, aThisObj) {
this._handlers.push({id: aId, callback: aCallback, obj: aThisObj});
},
_handlers: [],
updateSiteMenu: function updateSiteMenu() {
this._handlers.forEach(function(action) {
let node = document.getElementById(action.id);
if (node)
node.hidden = !action.callback.call(action.obj, node);
});
this._updateAttributes();
},
get _loginManager() {
delete this._loginManager;
return this._loginManager = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
},
// Permissions we track in Page Actions
_permissions: ["popup", "offline-app", "geolocation", "desktop-notification"],
_forEachPermissions: function _forEachPermissions(aHost, aCallback) {
let pm = Services.perms;
for (let i = 0; i < this._permissions.length; i++) {
let type = this._permissions[i];
if (!pm.testPermission(aHost, type))
continue;
let perms = pm.enumerator;
while (perms.hasMoreElements()) {
let permission = perms.getNext().QueryInterface(Ci.nsIPermission);
if (permission.host == aHost.asciiHost && permission.type == type)
aCallback(type);
}
}
},
updatePagePermissions: function updatePagePermissions(aNode) {
let host = Browser.selectedBrowser.currentURI;
let permissions = [];
this._forEachPermissions(host, function(aType) {
permissions.push("pageactions." + aType);
});
if (!this._loginManager.getLoginSavingEnabled(host.prePath)) {
// If rememberSignons is false, then getLoginSavingEnabled returns false
// for all pages, so we should just ignore it (Bug 601163).
if (Services.prefs.getBoolPref("signon.rememberSignons"))
permissions.push("pageactions.password");
}
let descriptions = permissions.map(function(s) Strings.browser.GetStringFromName(s));
aNode.setAttribute("description", descriptions.join(", "));
return (permissions.length > 0);
},
updateForgetPassword: function updateForgetPassword(aNode) {
let host = Browser.selectedBrowser.currentURI;
let logins = this._loginManager.findLogins({}, host.prePath, "", "");
return logins.some(function(login) login.hostname == host.prePath);
},
forgetPassword: function forgetPassword(aEvent) {
let host = Browser.selectedBrowser.currentURI;
let lm = this._loginManager;
lm.findLogins({}, host.prePath, "", "").forEach(function(login) {
if (login.hostname == host.prePath)
lm.removeLogin(login);
});
this.hideItem(aEvent.target);
aEvent.stopPropagation(); // Don't hide the site menu.
},
clearPagePermissions: function clearPagePermissions(aEvent) {
let pm = Services.perms;
let host = Browser.selectedBrowser.currentURI;
this._forEachPermissions(host, function(aType) {
pm.remove(host.asciiHost, aType);
// reset the 'remember' counter for permissions that support it
if (["geolocation", "desktop-notification"].indexOf(aType) != -1)
Services.contentPrefs.setPref(host.asciiHost, aType + ".request.remember", 0);
});
let lm = this._loginManager;
if (!lm.getLoginSavingEnabled(host.prePath))
lm.setLoginSavingEnabled(host.prePath, true);
this.hideItem(aEvent.target);
aEvent.stopPropagation(); // Don't hide the site menu.
},
savePageAsPDF: function saveAsPDF() {
let browser = Browser.selectedBrowser;
let fileName = ContentAreaUtils.getDefaultFileName(browser.contentTitle, browser.documentURI, null, null);
fileName = fileName.trim() + ".pdf";
let dm = Cc["@mozilla.org/download-manager;1"].getService(Ci.nsIDownloadManager);
let downloadsDir = dm.defaultDownloadsDirectory;
#ifdef ANDROID
// Create the final destination file location
let file = downloadsDir.clone();
file.append(fileName);
file.createUnique(file.NORMAL_FILE_TYPE, 0666);
#else
let picker = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
picker.init(window, Strings.browser.GetStringFromName("pageactions.saveas.pdf"), Ci.nsIFilePicker.modeSave);
picker.appendFilter("PDF", "*.pdf");
picker.defaultExtension = "pdf";
picker.defaultString = fileName;
picker.displayDirectory = downloadsDir;
let rv = picker.show();
if (rv == Ci.nsIFilePicker.returnCancel)
return;
let file = picker.file;
#endif
fileName = file.leafName;
// We must manually add this to the download system
let db = dm.DBConnection;
let stmt = db.createStatement(
"INSERT INTO moz_downloads (name, source, target, startTime, endTime, state, referrer) " +
"VALUES (:name, :source, :target, :startTime, :endTime, :state, :referrer)"
);
let current = browser.currentURI.spec;
stmt.params.name = fileName;
stmt.params.source = current;
stmt.params.target = Services.io.newFileURI(file).spec;
stmt.params.startTime = Date.now() * 1000;
stmt.params.endTime = Date.now() * 1000;
stmt.params.state = Ci.nsIDownloadManager.DOWNLOAD_NOTSTARTED;
stmt.params.referrer = current;
stmt.execute();
stmt.finalize();
let newItemId = db.lastInsertRowID;
let download = dm.getDownload(newItemId);
try {
DownloadsView.downloadStarted(download);
}
catch(e) {}
Services.obs.notifyObservers(download, "dl-start", null);
#ifdef ANDROID
let tmpDir = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
file = tmpDir.clone();
file.append(fileName);
#endif
let data = {
type: Ci.nsIPrintSettings.kOutputFormatPDF,
id: newItemId,
referrer: current,
filePath: file.path
};
Browser.selectedBrowser.messageManager.sendAsyncMessage("Browser:SaveAs", data);
},
updatePageSaveAs: function updatePageSaveAs(aNode) {
// Check for local XUL content
let contentWindow = Browser.selectedBrowser.contentWindow;
return !(contentWindow && contentWindow.document instanceof XULDocument);
},
updateShare: function updateShare(aNode) {
return Util.isShareableScheme(Browser.selectedBrowser.currentURI.scheme);
},
hideItem: function hideItem(aNode) {
aNode.hidden = true;
this._updateAttributes();
},
_updateAttributes: function _updateAttributes() {
let container = document.getElementById("pageactions-container");
let visibleNodes = container.querySelectorAll("pageaction:not([hidden=true])");
let visibleCount = visibleNodes.length;
for (let i = 0; i < visibleCount; i++)
visibleNodes[i].classList.remove("odd-last-child");
visibleNodes[visibleCount - 1].classList.add("last-child");
if (visibleCount % 2)
visibleNodes[visibleCount - 1].classList.add("odd");
}
};
var NewTabPopup = {
_timeout: 0,
_tabs: [],
@ -1306,172 +1076,6 @@ var ContextHelper = {
}
};
var SelectionHelper = {
enabled: true,
popupState: null,
target: null,
deltaX: -1,
deltaY: -1,
get _start() {
delete this._start;
return this._start = document.getElementById("selectionhandle-start");
},
get _end() {
delete this._end;
return this._end = document.getElementById("selectionhandle-end");
},
showPopup: function sh_showPopup(aMessage) {
if (!this.enabled || aMessage.json.types.indexOf("content-text") == -1)
return false;
this.popupState = aMessage.json;
this.popupState.target = aMessage.target;
this._start.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._end.customDragger = {
isDraggable: function isDraggable(target, content) { return { x: true, y: false }; },
dragStart: function dragStart(cx, cy, target, scroller) {},
dragStop: function dragStop(dx, dy, scroller) { return false; },
dragMove: function dragMove(dx, dy, scroller) { return false; }
};
this._start.addEventListener("TapUp", this, true);
this._end.addEventListener("TapUp", this, true);
messageManager.addMessageListener("Browser:SelectionRange", this);
messageManager.addMessageListener("Browser:SelectionCopied", this);
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionStart", { x: this.popupState.x, y: this.popupState.y });
// Hide the selection handles
window.addEventListener("TapDown", this, true);
window.addEventListener("resize", this, true);
window.addEventListener("keypress", this, true);
Elements.browsers.addEventListener("URLChanged", this, true);
Elements.browsers.addEventListener("SizeChanged", this, true);
Elements.browsers.addEventListener("ZoomChanged", this, true);
let event = document.createEvent("Events");
event.initEvent("CancelTouchSequence", true, false);
this.popupState.target.dispatchEvent(event);
return true;
},
hide: function sh_hide(aEvent) {
if (this._start.hidden)
return;
let pos = this.popupState.target.transformClientToBrowser(aEvent.clientX || 0, aEvent.clientY || 0);
let json = {
x: pos.x,
y: pos.y
};
try {
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionEnd", json);
} catch (e) {
Cu.reportError(e);
}
this.popupState = null;
this._start.hidden = true;
this._end.hidden = true;
this._start.removeEventListener("TapUp", this, true);
this._end.removeEventListener("TapUp", this, true);
messageManager.removeMessageListener("Browser:SelectionRange", this);
window.removeEventListener("TapDown", this, true);
window.removeEventListener("resize", this, true);
window.removeEventListener("keypress", this, true);
Elements.browsers.removeEventListener("URLChanged", this, true);
Elements.browsers.removeEventListener("SizeChanged", this, true);
Elements.browsers.removeEventListener("ZoomChanged", this, true);
},
handleEvent: function handleEvent(aEvent) {
switch (aEvent.type) {
case "TapDown":
if (aEvent.target == this._start || aEvent.target == this._end) {
this.target = aEvent.target;
this.deltaX = (aEvent.clientX - this.target.left);
this.deltaY = (aEvent.clientY - this.target.top);
window.addEventListener("TapMove", this, true);
} else {
this.hide(aEvent);
}
break;
case "TapUp":
window.removeEventListener("TapMove", this, true);
this.target = null;
this.deltaX = -1;
this.deltaY = -1;
break;
case "TapMove":
if (this.target) {
this.target.left = aEvent.clientX - this.deltaX;
this.target.top = aEvent.clientY - this.deltaY;
let rect = this.target.getBoundingClientRect();
let data = this.target == this._start ? { x: rect.right, y: rect.top, type: "start" } : { x: rect.left, y: rect.top, type: "end" };
let pos = this.popupState.target.transformClientToBrowser(data.x || 0, data.y || 0);
let json = {
type: data.type,
x: pos.x,
y: pos.y
};
this.popupState.target.messageManager.sendAsyncMessage("Browser:SelectionMove", json);
}
break;
case "resize":
case "SizeChanged":
case "ZoomChanged":
case "URLChanged":
case "keypress":
this.hide(aEvent);
break;
}
},
receiveMessage: function sh_receiveMessage(aMessage) {
let json = aMessage.json;
switch (aMessage.name) {
case "Browser:SelectionRange": {
let pos = this.popupState.target.transformBrowserToClient(json.start.x || 0, json.start.y || 0);
this._start.left = pos.x - 32;
this._start.top = pos.y + this.deltaY;
this._start.hidden = false;
pos = this.popupState.target.transformBrowserToClient(json.end.x || 0, json.end.y || 0);
this._end.left = pos.x;
this._end.top = pos.y;
this._end.hidden = false;
break;
}
case "Browser:SelectionCopied": {
messageManager.removeMessageListener("Browser:SelectionCopied", this);
if (json.succeeded) {
let toaster = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService);
toaster.showAlertNotification(null, Strings.browser.GetStringFromName("selectionHelper.textCopied"), "", false, "", null);
}
break;
}
}
}
};
var BadgeHandlers = {
_handlers: [
{
@ -1655,227 +1259,3 @@ var FullScreenVideo = {
});
}
};
var CharsetMenu = {
_strings: null,
_charsets: null,
get strings() {
if (!this._strings)
this._strings = Services.strings.createBundle("chrome://global/locale/charsetTitles.properties");
return this._strings;
},
init: function() {
PageActions.register("pageaction-charset", this.updatePageAction, this);
},
updatePageAction: function(aNode) {
let pref = Services.prefs.getComplexValue("browser.menu.showCharacterEncoding", Ci.nsIPrefLocalizedString).data;
if (pref == "true") {
let charset = getBrowser().documentCharsetInfo.forcedCharset;
if (charset) {
charset = charset.toString();
charset = charset.trim().toLowerCase();
aNode.setAttribute("description", this.strings.GetStringFromName(charset + ".title"));
} else if (aNode.hasAttribute("description")) {
aNode.removeAttribute("description");
}
}
return ("true" == pref)
},
_toMenuItems: function(aCharsets, aCurrent) {
let ret = [];
aCharsets.forEach(function (aSet) {
try {
let string = aSet.trim().toLowerCase();
ret.push({
label: this.strings.GetStringFromName(string + ".title"),
value: string,
selected: (string == aCurrent)
});
} catch(ex) { }
}, this);
return ret;
},
menu : {
dispatchEvent: function(aEvent) {
if (aEvent.type == "command")
CharsetMenu.setCharset(this.menupopup.children[this.selectedIndex].value);
},
menupopup: {
hasAttribute: function(aAttr) { return false; },
},
selectedIndex: -1
},
get charsets() {
if (!this._charsets) {
this._charsets = Services.prefs.getComplexValue("intl.charsetmenu.browser.static", Ci.nsIPrefLocalizedString).data.split(",");
}
let charsets = this._charsets;
let currentCharset = getBrowser().documentCharsetInfo.forcedCharset;
if (currentCharset) {
currentCharset = currentCharset.toString();
currentCharset = currentCharset.trim().toLowerCase();
if (charsets.indexOf(currentCharset) == -1)
charsets.splice(0, 0, currentCharset);
}
return this._toMenuItems(charsets, currentCharset);
},
show: function showCharsetMenu() {
this.menu.menupopup.children = this.charsets;
MenuListHelperUI.show(this.menu);
},
setCharset: function setCharset(aCharset) {
let browser = getBrowser();
browser.messageManager.sendAsyncMessage("Browser:SetCharset", {
charset: aCharset
});
let history = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
history.setCharsetForURI(browser.documentURI, aCharset);
}
};
var WebappsUI = {
_dialog: null,
_manifest: null,
_perms: [],
checkBox: function(aEvent) {
let elem = aEvent.originalTarget;
let perm = elem.getAttribute("perm");
if (this._manifest.capabilities && this._manifest.capabilities.indexOf(perm) != -1) {
if (elem.checked) {
elem.classList.remove("webapps-noperm");
elem.classList.add("webapps-perm");
} else {
elem.classList.remove("webapps-perm");
elem.classList.add("webapps-noperm");
}
}
},
show: function show(aManifest) {
if (!aManifest) {
// Try every way to get an icon
let browser = Browser.selectedBrowser;
let icon = browser.appIcon.href;
if (!icon)
icon = browser.mIconURL;
if (!icon)
icon = gFaviconService.getFaviconImageForPage(browser.currentURI).spec;
// Create a simple manifest
aManifest = {
uri: browser.currentURI.spec,
name: browser.contentTitle,
icon: icon,
capabilities: [],
};
}
this._manifest = aManifest;
this._dialog = importDialog(window, "chrome://browser/content/webapps.xul", null);
if (aManifest.name)
document.getElementById("webapps-title").value = aManifest.name;
if (aManifest.icon)
document.getElementById("webapps-icon").src = aManifest.icon;
let uri = Services.io.newURI(aManifest.uri, null, null);
let perms = [["offline", "offline-app"], ["geoloc", "geo"], ["notifications", "desktop-notification"]];
let self = this;
perms.forEach(function(tuple) {
let elem = document.getElementById("webapps-" + tuple[0] + "-checkbox");
let currentPerm = Services.perms.testExactPermission(uri, tuple[1]);
self._perms[tuple[1]] = (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION);
if ((aManifest.capabilities && (aManifest.capabilities.indexOf(tuple[1]) != -1)) || (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION))
elem.checked = true;
else
elem.checked = (currentPerm == Ci.nsIPermissionManager.ALLOW_ACTION);
elem.classList.remove("webapps-noperm");
elem.classList.add("webapps-perm");
});
BrowserUI.pushPopup(this, this._dialog);
// Force a modal dialog
this._dialog.waitForClose();
},
hide: function hide() {
this._dialog.close();
this._dialog = null;
BrowserUI.popPopup(this);
},
_updatePermission: function updatePermission(aId, aPerm) {
try {
let uri = Services.io.newURI(this._manifest.uri, null, null);
let currentState = document.getElementById(aId).checked;
if (currentState != this._perms[aPerm])
Services.perms.add(uri, aPerm, currentState ? Ci.nsIPermissionManager.ALLOW_ACTION : Ci.nsIPermissionManager.DENY_ACTION);
} catch(e) {
Cu.reportError(e);
}
},
launch: function launch() {
let title = document.getElementById("webapps-title").value;
if (!title)
return;
this._updatePermission("webapps-offline-checkbox", "offline-app");
this._updatePermission("webapps-geoloc-checkbox", "geo");
this._updatePermission("webapps-notifications-checkbox", "desktop-notification");
this.hide();
this.install(this._manifest.uri, title, this._manifest.icon);
},
updateWebappsInstall: function updateWebappsInstall(aNode) {
if (document.getElementById("main-window").hasAttribute("webapp"))
return false;
let browser = Browser.selectedBrowser;
let webapp = Cc["@mozilla.org/webapps/support;1"].getService(Ci.nsIWebappsSupport);
return !(webapp && webapp.isApplicationInstalled(browser.currentURI.spec));
},
install: function(aURI, aTitle, aIcon) {
const kIconSize = 64;
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
canvas.setAttribute("style", "display: none");
let self = this;
let image = new Image();
image.onload = function() {
canvas.width = canvas.height = kIconSize; // clears the canvas
let ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, kIconSize, kIconSize);
let data = canvas.toDataURL("image/png", "");
canvas = null;
try {
let webapp = Cc["@mozilla.org/webapps/support;1"].getService(Ci.nsIWebappsSupport);
webapp.installApplication(aTitle, aURI, aIcon, data);
} catch(e) {
Cu.reportError(e);
}
}
image.onerror = function() {
// can't load the icon (bad URI) : fallback to the default one from chrome
self.install(aURI, aTitle, "chrome://browser/skin/images/favicon-default-30.png");
}
image.src = aIcon;
}
};

View File

@ -85,10 +85,10 @@
<method name="_onUndo">
<body>
<![CDATA[
let closeFn = new Function("event", this._container.getAttribute("onreloadtab"));
let container = this._container;
let closeFn = new Function("event", container.getAttribute("onreloadtab"));
closeFn.call(this);
this._container.removeTab(this);
container.removeClosedTab(this);
]]>
</body>
</method>

View File

@ -23,12 +23,15 @@ chrome.jar:
* content/AwesomePanel.js (content/AwesomePanel.js)
content/BookmarkHelper.js (content/BookmarkHelper.js)
content/BookmarkPopup.js (content/BookmarkPopup.js)
content/CharsetMenu.js (content/CharsetMenu.js)
content/ContentPopupHelper.js (content/ContentPopupHelper.js)
* content/ContextCommands.js (content/ContextCommands.js)
content/IndexedDB.js (content/IndexedDB.js)
content/MenuListHelperUI.js (content/MenuListHelperUI.js)
content/OfflineApps.js (content/OfflineApps.js)
* content/PageActions.js (content/PageActions.js)
content/SelectHelperUI.js (content/SelectHelperUI.js)
content/SelectionHelper.js (content/SelectionHelper.js)
content/SharingUI.js (content/SharingUI.js)
content/TabsPopup.js (content/TabsPopup.js)
content/MasterPasswordUI.js (content/MasterPasswordUI.js)
@ -66,6 +69,7 @@ chrome.jar:
content/prompt/prompt.js (content/prompt/prompt.js)
content/share.xul (content/share.xul)
content/webapps.xul (content/webapps.xul)
content/WebappsUI.js (content/WebappsUI.js)
content/masterPassword.xul (content/masterPassword.xul)
content/removeMasterPassword.xul (content/removeMasterPassword.xul)
content/AnimatedZoom.js (content/AnimatedZoom.js)

View File

@ -383,7 +383,7 @@ Prompt.prototype = {
let dialog = this.openDialog("chrome://browser/content/prompt/confirm.xul", params);
let doc = this._doc;
this._setupPrompt(doc, "prompt", aTitle, aText, {value: aCheckState.value, msg: aCheckMsg});
this._setupPrompt(doc, "confirm", aTitle, aText, {value: aCheckState.value, msg: aCheckMsg});
dialog.waitForClose();
return params.result;

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