mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge mozilla-central to mozilla-inbound
This commit is contained in:
commit
e2a4cc14b8
@ -229,10 +229,11 @@ public:
|
||||
// Return true if we can activate autoplay assuming enough data has arrived.
|
||||
bool CanActivateAutoplay();
|
||||
|
||||
// Notify that enough data has arrived to start autoplaying.
|
||||
// Notify that state has changed that might cause an autoplay element to
|
||||
// start playing.
|
||||
// If the element is 'autoplay' and is ready to play back (not paused,
|
||||
// autoplay pref enabled, etc), it should start playing back.
|
||||
virtual void NotifyAutoplayDataReady() MOZ_FINAL MOZ_OVERRIDE;
|
||||
void CheckAutoplayDataReady();
|
||||
|
||||
// Check if the media element had crossorigin set when loading started
|
||||
bool ShouldCheckAllowOrigin();
|
||||
|
@ -2215,9 +2215,7 @@ nsresult HTMLMediaElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
if (aNotify && aNameSpaceID == kNameSpaceID_None) {
|
||||
if (aName == nsGkAtoms::autoplay) {
|
||||
StopSuspendingAfterFirstFrame();
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
|
||||
NotifyAutoplayDataReady();
|
||||
}
|
||||
CheckAutoplayDataReady();
|
||||
// This attribute can affect AddRemoveSelfReference
|
||||
AddRemoveSelfReference();
|
||||
UpdatePreloadAction();
|
||||
@ -2467,8 +2465,7 @@ public:
|
||||
mHaveCurrentData(false),
|
||||
mBlocked(false),
|
||||
mMutex("HTMLMediaElement::StreamListener"),
|
||||
mPendingNotifyOutput(false),
|
||||
mDidHaveCurrentData(false)
|
||||
mPendingNotifyOutput(false)
|
||||
{}
|
||||
void Forget() { mElement = nullptr; }
|
||||
|
||||
@ -2535,22 +2532,13 @@ public:
|
||||
NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished);
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||
}
|
||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph,
|
||||
bool aHasCurrentData)
|
||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mDidHaveCurrentData == aHasCurrentData)
|
||||
return;
|
||||
mDidHaveCurrentData = aHasCurrentData;
|
||||
// Ignore the case where aHasCurrentData is false. If aHasCurrentData
|
||||
// changes from true to false, we don't worry about it. Video elements
|
||||
// preserve the last played frame anyway.
|
||||
if (aHasCurrentData) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData);
|
||||
aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
|
||||
}
|
||||
}
|
||||
virtual void NotifyOutput(MediaStreamGraph* aGraph)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
@ -2571,7 +2559,6 @@ private:
|
||||
// mMutex protects the fields below; they can be accessed on any thread
|
||||
Mutex mMutex;
|
||||
bool mPendingNotifyOutput;
|
||||
bool mDidHaveCurrentData;
|
||||
};
|
||||
|
||||
void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
|
||||
@ -2854,6 +2841,9 @@ void HTMLMediaElement::SeekCompleted()
|
||||
void HTMLMediaElement::NotifySuspendedByCache(bool aIsSuspended)
|
||||
{
|
||||
mDownloadSuspendedByCache = aIsSuspended;
|
||||
// If this is an autoplay element, we may need to kick off its autoplaying
|
||||
// now so we consume data and hopefully free up cache space.
|
||||
CheckAutoplayDataReady();
|
||||
}
|
||||
|
||||
void HTMLMediaElement::DownloadSuspended()
|
||||
@ -2992,9 +2982,7 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("canplay"));
|
||||
}
|
||||
|
||||
if (mReadyState == nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) {
|
||||
NotifyAutoplayDataReady();
|
||||
}
|
||||
CheckAutoplayDataReady();
|
||||
|
||||
if (oldState < nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
||||
mReadyState >= nsIDOMHTMLMediaElement::HAVE_FUTURE_DATA &&
|
||||
@ -3010,14 +2998,20 @@ void HTMLMediaElement::ChangeReadyState(nsMediaReadyState aState)
|
||||
|
||||
bool HTMLMediaElement::CanActivateAutoplay()
|
||||
{
|
||||
// For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
|
||||
// this element itself might be blocking the stream from making progress by
|
||||
// being paused.
|
||||
return mAutoplaying &&
|
||||
mPaused &&
|
||||
(mDownloadSuspendedByCache ||
|
||||
(mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
|
||||
(mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
|
||||
mAutoplayEnabled &&
|
||||
!IsEditable();
|
||||
}
|
||||
|
||||
void HTMLMediaElement::NotifyAutoplayDataReady()
|
||||
void HTMLMediaElement::CheckAutoplayDataReady()
|
||||
{
|
||||
if (CanActivateAutoplay()) {
|
||||
mPaused = false;
|
||||
|
@ -48,6 +48,8 @@ public:
|
||||
mEngine(aEngine),
|
||||
mKind(aKind)
|
||||
{
|
||||
// AudioNodes are always producing data
|
||||
mHasCurrentData = true;
|
||||
}
|
||||
~AudioNodeStream();
|
||||
|
||||
|
@ -952,11 +952,6 @@ void MediaDecoder::NotifySuspendedStatusChanged()
|
||||
bool suspended = mResource->IsSuspendedByCache(&activeStream);
|
||||
|
||||
if (mOwner) {
|
||||
if (suspended) {
|
||||
// If this is an autoplay element, we need to kick off its autoplaying
|
||||
// now so we consume data and hopefully free up cache space.
|
||||
mOwner->NotifyAutoplayDataReady();
|
||||
}
|
||||
mOwner->NotifySuspendedByCache(suspended);
|
||||
UpdateReadyStateForData();
|
||||
}
|
||||
|
@ -109,11 +109,6 @@ public:
|
||||
// ongoing.
|
||||
virtual void DownloadResumed(bool aForceNetworkLoading = false) = 0;
|
||||
|
||||
// Notify that enough data has arrived to start autoplaying.
|
||||
// If the element is 'autoplay' and is ready to play back (not paused,
|
||||
// autoplay pref enabled, etc), it should start playing back.
|
||||
virtual void NotifyAutoplayDataReady() = 0;
|
||||
|
||||
// Called by the media decoder to indicate whether the media cache has
|
||||
// suspended the channel.
|
||||
virtual void NotifySuspendedByCache(bool aIsSuspended) = 0;
|
||||
|
@ -175,6 +175,9 @@ MediaStreamGraphImpl::ExtractPendingInput(SourceMediaStream* aStream,
|
||||
}
|
||||
aStream->mBuffer.AdvanceKnownTracksTime(aStream->mUpdateKnownTracksTime);
|
||||
}
|
||||
if (aStream->mBuffer.GetEnd() > 0) {
|
||||
aStream->mHasCurrentData = true;
|
||||
}
|
||||
if (finished) {
|
||||
FinishStream(aStream);
|
||||
}
|
||||
@ -659,10 +662,12 @@ MediaStreamGraphImpl::RecomputeBlockingAt(const nsTArray<MediaStream*>& aStreams
|
||||
void
|
||||
MediaStreamGraphImpl::NotifyHasCurrentData(MediaStream* aStream)
|
||||
{
|
||||
if (!aStream->mNotifiedHasCurrentData && aStream->mHasCurrentData) {
|
||||
for (uint32_t j = 0; j < aStream->mListeners.Length(); ++j) {
|
||||
MediaStreamListener* l = aStream->mListeners[j];
|
||||
l->NotifyHasCurrentData(this,
|
||||
GraphTimeToStreamTime(aStream, mCurrentTime) < aStream->mBuffer.GetEnd());
|
||||
l->NotifyHasCurrentData(this);
|
||||
}
|
||||
aStream->mNotifiedHasCurrentData = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1577,6 +1582,9 @@ MediaStream::AddListenerImpl(already_AddRefed<MediaStreamListener> aListener)
|
||||
if (mNotifiedFinished) {
|
||||
listener->NotifyFinished(GraphImpl());
|
||||
}
|
||||
if (mNotifiedHasCurrentData) {
|
||||
listener->NotifyHasCurrentData(GraphImpl());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -128,10 +128,12 @@ public:
|
||||
virtual void NotifyBlockingChanged(MediaStreamGraph* aGraph, Blocking aBlocked) {}
|
||||
|
||||
/**
|
||||
* Notify that the stream has (or does not have) data in each track
|
||||
* for the stream's current time.
|
||||
* Notify that the stream has data in each track
|
||||
* for the stream's current time. Once this state becomes true, it will
|
||||
* always be true since we block stream time from progressing to times where
|
||||
* there isn't data in each track.
|
||||
*/
|
||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph, bool aHasCurrentData) {}
|
||||
virtual void NotifyHasCurrentData(MediaStreamGraph* aGraph) {}
|
||||
|
||||
/**
|
||||
* Notify that the stream output is advancing.
|
||||
@ -268,6 +270,8 @@ public:
|
||||
, mFinished(false)
|
||||
, mNotifiedFinished(false)
|
||||
, mNotifiedBlocked(false)
|
||||
, mHasCurrentData(false)
|
||||
, mNotifiedHasCurrentData(false)
|
||||
, mWrapper(aWrapper)
|
||||
, mMainThreadCurrentTime(0)
|
||||
, mMainThreadFinished(false)
|
||||
@ -421,6 +425,8 @@ public:
|
||||
bool IsFinishedOnGraphThread() { return mFinished; }
|
||||
void FinishOnGraphThread();
|
||||
|
||||
bool HasCurrentData() { return mHasCurrentData; }
|
||||
|
||||
protected:
|
||||
virtual void AdvanceTimeVaryingValuesToCurrentTime(GraphTime aCurrentTime, GraphTime aBlockedTime)
|
||||
{
|
||||
@ -503,6 +509,17 @@ protected:
|
||||
* indicated that the stream is blocked.
|
||||
*/
|
||||
bool mNotifiedBlocked;
|
||||
/**
|
||||
* True if some data can be present by this stream if/when it's unblocked.
|
||||
* Set by the stream itself on the MediaStreamGraph thread. Only changes
|
||||
* from false to true once a stream has data, since we won't
|
||||
* unblock it until there's more data.
|
||||
*/
|
||||
bool mHasCurrentData;
|
||||
/**
|
||||
* True if mHasCurrentData is true and we've notified listeners.
|
||||
*/
|
||||
bool mNotifiedHasCurrentData;
|
||||
|
||||
// Temporary data for ordering streams by dependency graph
|
||||
bool mHasBeenOrdered;
|
||||
|
@ -47,11 +47,15 @@ public:
|
||||
mappedTracksWithMatchingInputTracks.AppendElement(false);
|
||||
}
|
||||
bool allFinished = true;
|
||||
bool allHaveCurrentData = true;
|
||||
for (uint32_t i = 0; i < mInputs.Length(); ++i) {
|
||||
MediaStream* stream = mInputs[i]->GetSource();
|
||||
if (!stream->IsFinishedOnGraphThread()) {
|
||||
allFinished = false;
|
||||
}
|
||||
if (!stream->HasCurrentData()) {
|
||||
allHaveCurrentData = false;
|
||||
}
|
||||
for (StreamBuffer::TrackIter tracks(stream->GetStreamBuffer());
|
||||
!tracks.IsEnded(); tracks.Next()) {
|
||||
bool found = false;
|
||||
@ -97,6 +101,10 @@ public:
|
||||
FinishOnGraphThread();
|
||||
}
|
||||
mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
|
||||
if (allHaveCurrentData) {
|
||||
// We can make progress if we're not blocked
|
||||
mHasCurrentData = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -14,6 +14,7 @@ const Cu = Components.utils;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
Cu.import("resource://gre/modules/ObjectWrapper.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
|
||||
return Cc["@mozilla.org/dom/dom-request-service;1"].getService(Ci.nsIDOMRequestService);
|
||||
@ -454,7 +455,8 @@ ContactManager.prototype = {
|
||||
return contact;
|
||||
});
|
||||
if (DEBUG) debug("result: " + JSON.stringify(result));
|
||||
Services.DOMRequest.fireSuccess(req.request, result);
|
||||
Services.DOMRequest.fireSuccess(req.request,
|
||||
ObjectWrapper.wrap(result, this._window));
|
||||
} else {
|
||||
if (DEBUG) debug("no request stored!" + msg.requestID);
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ function testImportSimContacts() {
|
||||
request.onsuccess = function onsuccess() {
|
||||
let simContacts = request.result;
|
||||
|
||||
is(Array.isArray(simContacts), true);
|
||||
|
||||
// These SIM contacts are harded in external/qemu/telephony/sim_card.c
|
||||
is(simContacts[0].name, "Mozilla");
|
||||
is(simContacts[0].tel[0].value, "15555218201");
|
||||
|
@ -26,7 +26,7 @@ interface nsIDOMMozMmsMessage : nsISupports
|
||||
/**
|
||||
* Should be "not-downloaded", "received", "sending", "sent" or "error".
|
||||
*/
|
||||
readonly attribute DOMString state;
|
||||
readonly attribute DOMString delivery;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval deliveryStatus; // DOMString[]
|
||||
|
@ -16,10 +16,6 @@ interface nsIDOMMozSmsMessage : nsISupports
|
||||
|
||||
/**
|
||||
* Should be "received", "sending", "sent" or "error".
|
||||
*
|
||||
* TODO Bug 850530 Please see the IDL proposal at Bug 760065.
|
||||
* We need to s/delivery/state in nsIDOMMozSmsMessage, which sounds
|
||||
* a better name and can be consistent with nsIDOMMozMmsMessage.
|
||||
*/
|
||||
readonly attribute DOMString delivery;
|
||||
|
||||
|
@ -29,7 +29,7 @@ interface nsIMobileMessageService : nsISupports
|
||||
|
||||
[implicit_jscontext]
|
||||
nsIDOMMozMmsMessage createMmsMessage(in long id,
|
||||
in DOMString state,
|
||||
in DOMString delivery,
|
||||
in jsval deliveryStatus,
|
||||
in DOMString sender,
|
||||
in jsval receivers,
|
||||
|
@ -31,7 +31,7 @@ NS_IMPL_ADDREF(MmsMessage)
|
||||
NS_IMPL_RELEASE(MmsMessage)
|
||||
|
||||
MmsMessage::MmsMessage(int32_t aId,
|
||||
DeliveryState aState,
|
||||
DeliveryState aDelivery,
|
||||
const nsTArray<DeliveryStatus>& aDeliveryStatus,
|
||||
const nsAString& aSender,
|
||||
const nsTArray<nsString>& aReceivers,
|
||||
@ -41,7 +41,7 @@ MmsMessage::MmsMessage(int32_t aId,
|
||||
const nsAString& aSmil,
|
||||
const nsTArray<MmsAttachment>& aAttachments)
|
||||
: mId(aId),
|
||||
mState(aState),
|
||||
mDelivery(aDelivery),
|
||||
mDeliveryStatus(aDeliveryStatus),
|
||||
mSender(aSender),
|
||||
mReceivers(aReceivers),
|
||||
@ -55,7 +55,7 @@ MmsMessage::MmsMessage(int32_t aId,
|
||||
|
||||
/* static */ nsresult
|
||||
MmsMessage::Create(int32_t aId,
|
||||
const nsAString& aState,
|
||||
const nsAString& aDelivery,
|
||||
const JS::Value& aDeliveryStatus,
|
||||
const nsAString& aSender,
|
||||
const JS::Value& aReceivers,
|
||||
@ -69,18 +69,18 @@ MmsMessage::Create(int32_t aId,
|
||||
{
|
||||
*aMessage = nullptr;
|
||||
|
||||
// Set |state|.
|
||||
DeliveryState state;
|
||||
if (aState.Equals(DELIVERY_SENT)) {
|
||||
state = eDeliveryState_Sent;
|
||||
} else if (aState.Equals(DELIVERY_RECEIVED)) {
|
||||
state = eDeliveryState_Received;
|
||||
} else if (aState.Equals(DELIVERY_SENDING)) {
|
||||
state = eDeliveryState_Sending;
|
||||
} else if (aState.Equals(DELIVERY_NOT_DOWNLOADED)) {
|
||||
state = eDeliveryState_NotDownloaded;
|
||||
} else if (aState.Equals(DELIVERY_ERROR)) {
|
||||
state = eDeliveryState_Error;
|
||||
// Set |delivery|.
|
||||
DeliveryState delivery;
|
||||
if (aDelivery.Equals(DELIVERY_SENT)) {
|
||||
delivery = eDeliveryState_Sent;
|
||||
} else if (aDelivery.Equals(DELIVERY_RECEIVED)) {
|
||||
delivery = eDeliveryState_Received;
|
||||
} else if (aDelivery.Equals(DELIVERY_SENDING)) {
|
||||
delivery = eDeliveryState_Sending;
|
||||
} else if (aDelivery.Equals(DELIVERY_NOT_DOWNLOADED)) {
|
||||
delivery = eDeliveryState_NotDownloaded;
|
||||
} else if (aDelivery.Equals(DELIVERY_ERROR)) {
|
||||
delivery = eDeliveryState_Error;
|
||||
} else {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@ -193,7 +193,7 @@ MmsMessage::Create(int32_t aId,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMMozMmsMessage> message = new MmsMessage(aId,
|
||||
state,
|
||||
delivery,
|
||||
deliveryStatus,
|
||||
aSender,
|
||||
receivers,
|
||||
@ -221,23 +221,23 @@ MmsMessage::GetId(int32_t* aId)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
MmsMessage::GetState(nsAString& aState)
|
||||
MmsMessage::GetDelivery(nsAString& aDelivery)
|
||||
{
|
||||
switch (mState) {
|
||||
switch (mDelivery) {
|
||||
case eDeliveryState_Received:
|
||||
aState = DELIVERY_RECEIVED;
|
||||
aDelivery = DELIVERY_RECEIVED;
|
||||
break;
|
||||
case eDeliveryState_Sending:
|
||||
aState = DELIVERY_SENDING;
|
||||
aDelivery = DELIVERY_SENDING;
|
||||
break;
|
||||
case eDeliveryState_Sent:
|
||||
aState = DELIVERY_SENT;
|
||||
aDelivery = DELIVERY_SENT;
|
||||
break;
|
||||
case eDeliveryState_Error:
|
||||
aState = DELIVERY_ERROR;
|
||||
aDelivery = DELIVERY_ERROR;
|
||||
break;
|
||||
case eDeliveryState_NotDownloaded:
|
||||
aState = DELIVERY_NOT_DOWNLOADED;
|
||||
aDelivery = DELIVERY_NOT_DOWNLOADED;
|
||||
break;
|
||||
case eDeliveryState_Unknown:
|
||||
case eDeliveryState_EndGuard:
|
||||
@ -252,8 +252,8 @@ MmsMessage::GetState(nsAString& aState)
|
||||
NS_IMETHODIMP
|
||||
MmsMessage::GetDeliveryStatus(JSContext* aCx, JS::Value* aDeliveryStatus)
|
||||
{
|
||||
// TODO Bug 850525 It would be better to depend on the state of MmsMessage
|
||||
// to return a more correct value. Ex, when .state = 'received', we should
|
||||
// TODO Bug 850525 It'd be better to depend on the delivery of MmsMessage
|
||||
// to return a more correct value. Ex, if .delivery = 'received', we should
|
||||
// also make .deliveryStatus = null, since the .deliveryStatus is useless.
|
||||
uint32_t length = mDeliveryStatus.Length();
|
||||
if (length == 0) {
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
NS_DECL_NSIDOMMOZMMSMESSAGE
|
||||
|
||||
MmsMessage(int32_t aId,
|
||||
mobilemessage::DeliveryState aState,
|
||||
mobilemessage::DeliveryState aDelivery,
|
||||
const nsTArray<mobilemessage::DeliveryStatus>& aDeliveryStatus,
|
||||
const nsAString& aSender,
|
||||
const nsTArray<nsString>& aReceivers,
|
||||
@ -34,7 +34,7 @@ public:
|
||||
const nsTArray<idl::MmsAttachment>& aAttachments);
|
||||
|
||||
static nsresult Create(int32_t aId,
|
||||
const nsAString& aState,
|
||||
const nsAString& aDelivery,
|
||||
const JS::Value& aDeliveryStatus,
|
||||
const nsAString& aSender,
|
||||
const JS::Value& aReceivers,
|
||||
@ -49,7 +49,7 @@ public:
|
||||
private:
|
||||
|
||||
int32_t mId;
|
||||
mobilemessage::DeliveryState mState;
|
||||
mobilemessage::DeliveryState mDelivery;
|
||||
nsTArray<mobilemessage::DeliveryStatus> mDeliveryStatus;
|
||||
nsString mSender;
|
||||
nsTArray<nsString> mReceivers;
|
||||
|
@ -56,7 +56,7 @@ MobileMessageService::CreateSmsMessage(int32_t aId,
|
||||
|
||||
NS_IMETHODIMP
|
||||
MobileMessageService::CreateMmsMessage(int32_t aId,
|
||||
const nsAString& aState,
|
||||
const nsAString& aDelivery,
|
||||
const JS::Value& aDeliveryStatus,
|
||||
const nsAString& aSender,
|
||||
const JS::Value& aReceivers,
|
||||
@ -69,7 +69,7 @@ MobileMessageService::CreateMmsMessage(int32_t aId,
|
||||
nsIDOMMozMmsMessage** aMessage)
|
||||
{
|
||||
return MmsMessage::Create(aId,
|
||||
aState,
|
||||
aDelivery,
|
||||
aDeliveryStatus,
|
||||
aSender,
|
||||
aReceivers,
|
||||
|
@ -1153,9 +1153,10 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
} else if (mShadowTarget) {
|
||||
if (mWidget) {
|
||||
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
|
||||
nsRefPtr<gfxASurface> target = mShadowTarget->OriginalSurface();
|
||||
nsIntRect bounds;
|
||||
mWidget->GetBounds(bounds);
|
||||
SurfaceDescriptor inSnapshot, snapshot;
|
||||
if (AllocBuffer(target->GetSize(), target->GetContentType(),
|
||||
if (AllocBuffer(bounds.Size(), gfxASurface::CONTENT_COLOR_ALPHA,
|
||||
&inSnapshot) &&
|
||||
// The compositor will usually reuse |snapshot| and return
|
||||
// it through |outSnapshot|, but if it doesn't, it's
|
||||
@ -1164,8 +1165,6 @@ BasicShadowLayerManager::EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
AutoOpenSurface opener(OPEN_READ_ONLY, snapshot);
|
||||
gfxASurface* source = opener.Get();
|
||||
|
||||
gfxContextAutoSaveRestore restore(mShadowTarget);
|
||||
mShadowTarget->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
mShadowTarget->DrawSurface(source, source->GetSize());
|
||||
}
|
||||
if (IsSurfaceDescriptorValid(snapshot)) {
|
||||
|
@ -85,6 +85,20 @@ struct TypeInferenceSizes
|
||||
}
|
||||
};
|
||||
|
||||
// Data for tracking JIT-code memory usage.
|
||||
struct CodeSizes
|
||||
{
|
||||
size_t jaeger;
|
||||
size_t ion;
|
||||
size_t asmJS;
|
||||
size_t baseline;
|
||||
size_t regexp;
|
||||
size_t other;
|
||||
size_t unused;
|
||||
|
||||
CodeSizes() { memset(this, 0, sizeof(CodeSizes)); }
|
||||
};
|
||||
|
||||
// Holds data about a huge string (one which uses more HugeStringInfo::MinSize
|
||||
// bytes of memory), so we can report it individually.
|
||||
struct HugeStringInfo
|
||||
@ -118,17 +132,14 @@ struct RuntimeSizes
|
||||
size_t contexts;
|
||||
size_t dtoa;
|
||||
size_t temporary;
|
||||
size_t jaegerCode;
|
||||
size_t ionCode;
|
||||
size_t asmJSCode;
|
||||
size_t regexpCode;
|
||||
size_t unusedCode;
|
||||
size_t regexpData;
|
||||
size_t stack;
|
||||
size_t gcMarker;
|
||||
size_t mathCache;
|
||||
size_t scriptData;
|
||||
size_t scriptSources;
|
||||
|
||||
CodeSizes code;
|
||||
};
|
||||
|
||||
struct ZoneStats
|
||||
|
@ -118,6 +118,24 @@ class HandleBase {};
|
||||
template <typename T>
|
||||
class MutableHandleBase {};
|
||||
|
||||
/*
|
||||
* js::NullPtr acts like a NULL pointer in contexts that require a Handle.
|
||||
*
|
||||
* Handle provides an implicit constructor for js::NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
* callers can simply write:
|
||||
* foo(js::NullPtr());
|
||||
* which avoids creating a Rooted<JSObject*> just to pass NULL.
|
||||
*
|
||||
* This is the SpiderMonkey internal variant. js::NullPtr should be used in
|
||||
* preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API
|
||||
* symbols.
|
||||
*/
|
||||
struct NullPtr
|
||||
{
|
||||
static void * const constNullValue;
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
namespace JS {
|
||||
@ -136,13 +154,15 @@ CheckStackRoots(JSContext *cx);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Handle provides an implicit constructor for NullPtr so that, given:
|
||||
* JS::NullPtr acts like a NULL pointer in contexts that require a Handle.
|
||||
*
|
||||
* Handle provides an implicit constructor for JS::NullPtr so that, given:
|
||||
* foo(Handle<JSObject*> h);
|
||||
* callers can simply write:
|
||||
* foo(NullPtr());
|
||||
* foo(JS::NullPtr());
|
||||
* which avoids creating a Rooted<JSObject*> just to pass NULL.
|
||||
*/
|
||||
struct NullPtr
|
||||
struct JS_PUBLIC_API(NullPtr)
|
||||
{
|
||||
static void * const constNullValue;
|
||||
};
|
||||
@ -170,9 +190,15 @@ class Handle : public js::HandleBase<T>
|
||||
}
|
||||
|
||||
/* Create a handle for a NULL pointer. */
|
||||
Handle(NullPtr) {
|
||||
Handle(js::NullPtr) {
|
||||
typedef typename js::tl::StaticAssert<mozilla::IsPointer<T>::value>::result _;
|
||||
ptr = reinterpret_cast<const T *>(&NullPtr::constNullValue);
|
||||
ptr = reinterpret_cast<const T *>(&js::NullPtr::constNullValue);
|
||||
}
|
||||
|
||||
/* Create a handle for a NULL pointer. */
|
||||
Handle(JS::NullPtr) {
|
||||
typedef typename js::tl::StaticAssert<mozilla::IsPointer<T>::value>::result _;
|
||||
ptr = reinterpret_cast<const T *>(&JS::NullPtr::constNullValue);
|
||||
}
|
||||
|
||||
Handle(MutableHandle<T> handle) {
|
||||
@ -353,7 +379,7 @@ class InternalHandle<T*>
|
||||
* fromMarkedLocation().
|
||||
*/
|
||||
InternalHandle(T *field)
|
||||
: holder(reinterpret_cast<void * const *>(&JS::NullPtr::constNullValue)),
|
||||
: holder(reinterpret_cast<void * const *>(&js::NullPtr::constNullValue)),
|
||||
offset(uintptr_t(field))
|
||||
{}
|
||||
};
|
||||
|
@ -965,17 +965,20 @@ selfhosting_srcs := \
|
||||
selfhosted_out_h_deps := \
|
||||
$(selfhosting_srcs) \
|
||||
$(srcdir)/js.msg \
|
||||
$(srcdir)/builtin/macros.py \
|
||||
$(srcdir)/builtin/js2c.py \
|
||||
$(srcdir)/builtin/embedjs.py
|
||||
$(srcdir)/builtin/embedjs.py \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_DEBUG),1)
|
||||
selfhosting_embed_flags += -d
|
||||
selfhosting_defines += -DDEBUG
|
||||
endif
|
||||
|
||||
ifneq (,$(MOZ_ZLIB_LIBS)$(MOZ_GLUE_LDFLAGS))
|
||||
selfhosting_defines += -DUSE_ZLIB
|
||||
endif
|
||||
|
||||
selfhosted.out.h: $(selfhosted_out_h_deps)
|
||||
$(PYTHON) $(srcdir)/builtin/embedjs.py $(selfhosting_embed_flags) $@ \
|
||||
$(srcdir)/js.msg $(srcdir)/builtin/macros.py $(selfhosting_srcs)
|
||||
$(PYTHON) $(srcdir)/builtin/embedjs.py $(selfhosting_defines) \
|
||||
-p '$(CPP)' -m $(srcdir)/js.msg -o $@ $(selfhosting_srcs)
|
||||
|
||||
###############################################
|
||||
# BEGIN kludges for the Nitro assembler
|
||||
|
@ -1,4 +1,6 @@
|
||||
/*
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99:
|
||||
*
|
||||
* Copyright (C) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -25,6 +27,8 @@
|
||||
|
||||
#include "ExecutableAllocator.h"
|
||||
|
||||
#include "js/MemoryMetrics.h"
|
||||
|
||||
#if ENABLE_ASSEMBLER
|
||||
|
||||
#include "prmjtime.h"
|
||||
@ -40,23 +44,25 @@ ExecutablePool::~ExecutablePool()
|
||||
}
|
||||
|
||||
void
|
||||
ExecutableAllocator::sizeOfCode(size_t *jaeger, size_t *ion, size_t *asmJS, size_t *regexp, size_t *unused) const
|
||||
ExecutableAllocator::sizeOfCode(JS::CodeSizes *sizes) const
|
||||
{
|
||||
*jaeger = 0;
|
||||
*ion = 0;
|
||||
*asmJS = 0;
|
||||
*regexp = 0;
|
||||
*unused = 0;
|
||||
*sizes = JS::CodeSizes();
|
||||
|
||||
if (m_pools.initialized()) {
|
||||
for (ExecPoolHashSet::Range r = m_pools.all(); !r.empty(); r.popFront()) {
|
||||
ExecutablePool* pool = r.front();
|
||||
*jaeger += pool->m_jaegerCodeBytes;
|
||||
*ion += pool->m_ionCodeBytes;
|
||||
*asmJS += pool->m_asmJSCodeBytes;
|
||||
*regexp += pool->m_regexpCodeBytes;
|
||||
*unused += pool->m_allocation.size - pool->m_jaegerCodeBytes - pool->m_ionCodeBytes
|
||||
- pool->m_asmJSCodeBytes - pool->m_regexpCodeBytes;
|
||||
sizes->jaeger += pool->m_jaegerCodeBytes;
|
||||
sizes->ion += pool->m_ionCodeBytes;
|
||||
sizes->baseline += pool->m_baselineCodeBytes;
|
||||
sizes->asmJS += pool->m_asmJSCodeBytes;
|
||||
sizes->regexp += pool->m_regexpCodeBytes;
|
||||
sizes->other += pool->m_otherCodeBytes;
|
||||
sizes->unused += pool->m_allocation.size - pool->m_jaegerCodeBytes
|
||||
- pool->m_ionCodeBytes
|
||||
- pool->m_baselineCodeBytes
|
||||
- pool->m_asmJSCodeBytes
|
||||
- pool->m_regexpCodeBytes
|
||||
- pool->m_otherCodeBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +78,15 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
|
||||
|
||||
//#define DEBUG_STRESS_JSC_ALLOCATOR
|
||||
|
||||
namespace JS {
|
||||
struct CodeSizes;
|
||||
}
|
||||
|
||||
namespace JSC {
|
||||
|
||||
class ExecutableAllocator;
|
||||
|
||||
enum CodeKind { JAEGER_CODE, ION_CODE, REGEXP_CODE, ASMJS_CODE };
|
||||
enum CodeKind { JAEGER_CODE, ION_CODE, BASELINE_CODE, REGEXP_CODE, ASMJS_CODE, OTHER_CODE };
|
||||
|
||||
// These are reference-counted. A new one starts with a count of 1.
|
||||
class ExecutablePool {
|
||||
@ -108,8 +112,10 @@ private:
|
||||
// Number of bytes currently used for Method and Regexp JIT code.
|
||||
size_t m_jaegerCodeBytes;
|
||||
size_t m_ionCodeBytes;
|
||||
size_t m_baselineCodeBytes;
|
||||
size_t m_asmJSCodeBytes;
|
||||
size_t m_regexpCodeBytes;
|
||||
size_t m_otherCodeBytes;
|
||||
|
||||
public:
|
||||
// Flag for downstream use, whether to try to release references to this pool.
|
||||
@ -130,7 +136,8 @@ public:
|
||||
|
||||
ExecutablePool(ExecutableAllocator* allocator, Allocation a)
|
||||
: m_allocator(allocator), m_freePtr(a.pages), m_end(m_freePtr + a.size), m_allocation(a),
|
||||
m_refCount(1), m_jaegerCodeBytes(0), m_ionCodeBytes(0), m_asmJSCodeBytes(0), m_regexpCodeBytes(0),
|
||||
m_refCount(1), m_jaegerCodeBytes(0), m_ionCodeBytes(0), m_baselineCodeBytes(0),
|
||||
m_asmJSCodeBytes(0), m_regexpCodeBytes(0), m_otherCodeBytes(0),
|
||||
m_destroy(false), m_gcNumber(0)
|
||||
{ }
|
||||
|
||||
@ -155,8 +162,10 @@ private:
|
||||
switch (kind) {
|
||||
case JAEGER_CODE: m_jaegerCodeBytes += n; break;
|
||||
case ION_CODE: m_ionCodeBytes += n; break;
|
||||
case BASELINE_CODE: m_baselineCodeBytes += n; break;
|
||||
case ASMJS_CODE: m_asmJSCodeBytes += n; break;
|
||||
case REGEXP_CODE: m_regexpCodeBytes += n; break;
|
||||
case OTHER_CODE: m_otherCodeBytes += n; break;
|
||||
default: JS_NOT_REACHED("bad code kind"); break;
|
||||
}
|
||||
return result;
|
||||
@ -255,7 +264,7 @@ public:
|
||||
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
|
||||
}
|
||||
|
||||
void sizeOfCode(size_t *jaeger, size_t *ion, size_t *asmJS, size_t *regexp, size_t *unused) const;
|
||||
void sizeOfCode(JS::CodeSizes *sizes) const;
|
||||
|
||||
void setDestroyCallback(DestroyCallback destroyCallback) {
|
||||
this->destroyCallback = destroyCallback;
|
||||
|
@ -4,6 +4,30 @@
|
||||
|
||||
// FIXME(bug 844882): Parallel array properties should not be exposed.
|
||||
|
||||
// The mode asserts options object.
|
||||
#define TRY_PARALLEL(MODE) \
|
||||
((!MODE || MODE.mode === "par"))
|
||||
#define ASSERT_SEQUENTIAL_IS_OK(MODE) \
|
||||
do { if (MODE) AssertSequentialIsOK(MODE) } while(false)
|
||||
|
||||
// Slice array: see ComputeAllSliceBounds()
|
||||
#define SLICE_INFO(START, END) START, END, START, 0
|
||||
#define SLICE_START(ID) ((ID << 2) + 0)
|
||||
#define SLICE_END(ID) ((ID << 2) + 1)
|
||||
#define SLICE_POS(ID) ((ID << 2) + 2)
|
||||
|
||||
// How many items at a time do we do recomp. for parallel execution.
|
||||
// Note that filter currently assumes that this is no greater than 32
|
||||
// in order to make use of a bitset.
|
||||
#define CHUNK_SHIFT 5
|
||||
#define CHUNK_SIZE 32
|
||||
|
||||
// Safe versions of ARRAY.push(ELEMENT)
|
||||
#define ARRAY_PUSH(ARRAY, ELEMENT) \
|
||||
callFunction(std_Array_push, ARRAY, ELEMENT);
|
||||
#define ARRAY_SLICE(ARRAY, ELEMENT) \
|
||||
callFunction(std_Array_slice, ARRAY, ELEMENT);
|
||||
|
||||
/**
|
||||
* Determine the number of chunks of size CHUNK_SIZE;
|
||||
* note that the final chunk may be smaller than CHUNK_SIZE.
|
||||
|
@ -23,6 +23,8 @@
|
||||
JSMSG_EMPTY_ARRAY_REDUCE: false,
|
||||
*/
|
||||
|
||||
/* Utility macros */
|
||||
#define TO_UINT32(x) (x >>> 0)
|
||||
|
||||
/* cache built-in functions before applications can change them */
|
||||
var std_isFinite = isFinite;
|
||||
@ -138,4 +140,3 @@ function assert(b, info) {
|
||||
if (!b)
|
||||
AssertionFailed(info);
|
||||
}
|
||||
|
||||
|
@ -1,58 +1,166 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# ToCAsciiArray and ToCArray are from V8's js2c.py.
|
||||
#
|
||||
# Copyright 2012 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This utility converts JS files containing self-hosted builtins into a C
|
||||
# header file that can be embedded into SpiderMonkey.
|
||||
#
|
||||
# It expects error messages in the JS code to be referenced by their C enum
|
||||
# keys as literals.
|
||||
# It uses the C preprocessor to process its inputs.
|
||||
|
||||
from __future__ import with_statement
|
||||
import re, sys, os, js2c, fileinput
|
||||
import re, sys, os, fileinput, subprocess
|
||||
import shlex
|
||||
from optparse import OptionParser
|
||||
|
||||
def replaceErrorMsgs(source_files, messages_file, output_file):
|
||||
messages = buildMessagesTable(messages_file)
|
||||
# For cases where one key is a prefix of another, we need to check
|
||||
# for the longer one first. Using a reverse-sorted key list ensures that.
|
||||
message_keys = messages.keys()
|
||||
message_keys.sort(reverse=True)
|
||||
with open(output_file, 'w') as output:
|
||||
if len(source_files) == 0:
|
||||
return
|
||||
for line in fileinput.input(source_files):
|
||||
line = line if line[-1] == '\n' else line + '\n'
|
||||
output.write(replaceMessages(line, messages, message_keys))
|
||||
def ToCAsciiArray(lines):
|
||||
result = []
|
||||
for chr in lines:
|
||||
value = ord(chr)
|
||||
assert value < 128
|
||||
result.append(str(value))
|
||||
return ", ".join(result)
|
||||
|
||||
def buildMessagesTable(messages_file):
|
||||
table = {}
|
||||
pattern = re.compile(r"MSG_DEF\(([\w_]+),\s*(\d+)")
|
||||
for line in fileinput.input(messages_file):
|
||||
match = pattern.match(line)
|
||||
if match:
|
||||
table[match.group(1)] = match.group(2)
|
||||
return table
|
||||
def ToCArray(lines):
|
||||
result = []
|
||||
for chr in lines:
|
||||
result.append(str(ord(chr)))
|
||||
return ", ".join(result)
|
||||
|
||||
def replaceMessages(line, messages, message_keys):
|
||||
if not 'JSMSG_' in line:
|
||||
return line
|
||||
for key in message_keys:
|
||||
line = line.replace(key, messages[key])
|
||||
return line
|
||||
HEADER_TEMPLATE = """\
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace js {
|
||||
namespace selfhosted {
|
||||
static const char data[] = { %(sources_data)s };
|
||||
|
||||
%(sources_declaration)s
|
||||
|
||||
uint32_t GetCompressedSize() {
|
||||
return %(compressed_total_length)i;
|
||||
}
|
||||
|
||||
uint32_t GetRawScriptsSize() {
|
||||
return %(raw_total_length)i;
|
||||
}
|
||||
} // selfhosted
|
||||
} // js
|
||||
"""
|
||||
|
||||
RAW_SOURCES_DECLARATION = """\
|
||||
static const char *rawSources = reinterpret_cast<const char *>(data);
|
||||
"""
|
||||
|
||||
COMPRESSED_SOURCES_DECLARATION = """\
|
||||
static const unsigned char *compressedSources = reinterpret_cast<const unsigned char *>(data);
|
||||
"""
|
||||
|
||||
def embed(cpp, msgs, sources, c_out, js_out, env):
|
||||
# Clang seems to complain and not output anything if the extension of the
|
||||
# input is not something it recognizes, so just fake a .h here.
|
||||
tmp = 'selfhosted.js.h'
|
||||
with open(tmp, 'wb') as output:
|
||||
output.write('\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources]))
|
||||
cmdline = cpp + ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env] + [tmp]
|
||||
p = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
|
||||
processed = ''
|
||||
for line in p.stdout:
|
||||
if not line.startswith('#'):
|
||||
processed += line
|
||||
os.remove(tmp)
|
||||
with open(js_out, 'w') as output:
|
||||
output.write(processed)
|
||||
with open(c_out, 'w') as output:
|
||||
if 'USE_ZLIB' in env:
|
||||
import zlib
|
||||
compressed = zlib.compress(processed)
|
||||
data = ToCArray(compressed)
|
||||
output.write(HEADER_TEMPLATE % {
|
||||
'sources_data': data,
|
||||
'sources_declaration': COMPRESSED_SOURCES_DECLARATION,
|
||||
'compressed_total_length': len(compressed),
|
||||
'raw_total_length': len(processed)
|
||||
})
|
||||
else:
|
||||
data = ToCAsciiArray(processed)
|
||||
output.write(HEADER_TEMPLATE % {
|
||||
'sources_data': data,
|
||||
'sources_declaration': RAW_SOURCES_DECLARATION,
|
||||
'compressed_total_length': 0,
|
||||
'raw_total_length': len(processed)
|
||||
})
|
||||
|
||||
def process_msgs(cpp, msgs):
|
||||
# Clang seems to complain and not output anything if the extension of the
|
||||
# input is not something it recognizes, so just fake a .h here.
|
||||
tmp = 'selfhosted.msg.h'
|
||||
with open(tmp, 'wb') as output:
|
||||
output.write("""\
|
||||
#define hash #
|
||||
#define id(x) x
|
||||
#define hashify(x) id(hash)x
|
||||
#define MSG_DEF(name, id, argc, ex, msg) hashify(define) name id
|
||||
#include "%(msgs)s"
|
||||
""" % { 'msgs': msgs })
|
||||
p = subprocess.Popen(cpp + [tmp], stdout=subprocess.PIPE)
|
||||
processed = p.communicate()[0]
|
||||
os.remove(tmp)
|
||||
return processed
|
||||
|
||||
def main():
|
||||
debug = sys.argv[1] == '-d'
|
||||
if debug:
|
||||
sys.argv.pop(1)
|
||||
output_file = sys.argv[1]
|
||||
messages_file = sys.argv[2]
|
||||
macros_file = sys.argv[3]
|
||||
source_files = sys.argv[4:]
|
||||
combined_file = 'selfhosted.js'
|
||||
replaceErrorMsgs(source_files, messages_file, combined_file)
|
||||
combined_sources = js2c.JS2C([combined_file, macros_file], [output_file], { 'TYPE': 'CORE', 'COMPRESSION': 'off', 'DEBUG':debug })
|
||||
with open(combined_file, 'w') as output:
|
||||
output.write(combined_sources)
|
||||
env = {}
|
||||
def define_env(option, opt, value, parser):
|
||||
pair = value.split('=', 1)
|
||||
if len(pair) == 1:
|
||||
pair.append(1)
|
||||
env[pair[0]] = pair[1]
|
||||
p = OptionParser(usage="%prog [options] file")
|
||||
p.add_option('-D', action='callback', callback=define_env, type="string",
|
||||
metavar='var=[val]', help='Define a variable')
|
||||
p.add_option('-m', type='string', metavar='jsmsg', default='../js.msg',
|
||||
help='js.msg file')
|
||||
p.add_option('-p', type='string', metavar='cpp', help='Path to C preprocessor')
|
||||
p.add_option('-o', type='string', metavar='filename', default='selfhosted.out.h',
|
||||
help='C array header file')
|
||||
p.add_option('-s', type='string', metavar='jsfilename', default='selfhosted.js',
|
||||
help='Combined postprocessed JS file')
|
||||
(options, sources) = p.parse_args()
|
||||
if not (options.p and sources):
|
||||
p.print_help()
|
||||
exit(1)
|
||||
cpp = shlex.split(options.p)
|
||||
embed(cpp, process_msgs(cpp, options.m),
|
||||
sources, options.o, options.s, env)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
@ -1,351 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2012 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# This is a utility for converting JavaScript source code into C-style
|
||||
# char arrays. It is used for embedded JavaScript code in the V8
|
||||
# library.
|
||||
|
||||
import os, re, sys, string
|
||||
import jsmin
|
||||
import bz2
|
||||
|
||||
|
||||
def ToCAsciiArray(lines):
|
||||
result = []
|
||||
for chr in lines:
|
||||
value = ord(chr)
|
||||
assert value < 128
|
||||
result.append(str(value))
|
||||
return ", ".join(result)
|
||||
|
||||
|
||||
def ToCArray(lines):
|
||||
result = []
|
||||
for chr in lines:
|
||||
result.append(str(ord(chr)))
|
||||
return ", ".join(result)
|
||||
|
||||
|
||||
def RemoveCommentsAndTrailingWhitespace(lines):
|
||||
lines = re.sub(r'//.*\n', '\n', lines) # end-of-line comments
|
||||
lines = re.sub(re.compile(r'/\*.*?\*/', re.DOTALL), '', lines) # comments.
|
||||
lines = re.sub(r'\s+\n+', '\n', lines) # trailing whitespace
|
||||
return lines
|
||||
|
||||
|
||||
def ReadFile(filename):
|
||||
file = open(filename, "rt")
|
||||
try:
|
||||
lines = file.read()
|
||||
finally:
|
||||
file.close()
|
||||
return lines
|
||||
|
||||
|
||||
def ReadLines(filename):
|
||||
result = []
|
||||
for line in open(filename, "rt"):
|
||||
if '#' in line:
|
||||
line = line[:line.index('#')]
|
||||
line = line.strip()
|
||||
if len(line) > 0:
|
||||
result.append(line)
|
||||
return result
|
||||
|
||||
|
||||
def LoadConfigFrom(name):
|
||||
import ConfigParser
|
||||
config = ConfigParser.ConfigParser()
|
||||
config.read(name)
|
||||
return config
|
||||
|
||||
|
||||
def ParseValue(string):
|
||||
string = string.strip()
|
||||
if string.startswith('[') and string.endswith(']'):
|
||||
return string.lstrip('[').rstrip(']').split()
|
||||
else:
|
||||
return string
|
||||
|
||||
|
||||
EVAL_PATTERN = re.compile(r'\beval\s*\(')
|
||||
WITH_PATTERN = re.compile(r'\bwith\s*\(')
|
||||
|
||||
|
||||
def Validate(lines, file):
|
||||
lines = RemoveCommentsAndTrailingWhitespace(lines)
|
||||
# Because of simplified context setup, eval and with is not
|
||||
# allowed in the natives files.
|
||||
eval_match = EVAL_PATTERN.search(lines)
|
||||
if eval_match:
|
||||
raise ("Eval disallowed in natives: %s" % file)
|
||||
with_match = WITH_PATTERN.search(lines)
|
||||
if with_match:
|
||||
raise ("With statements disallowed in natives: %s" % file)
|
||||
|
||||
|
||||
def ExpandConstants(lines, constants):
|
||||
for key, value in constants:
|
||||
lines = key.sub(str(value), lines)
|
||||
return lines
|
||||
|
||||
|
||||
def ExpandMacros(lines, macros):
|
||||
# We allow macros to depend on the previously declared macros, but
|
||||
# we don't allow self-dependecies or recursion.
|
||||
for name_pattern, macro in reversed(macros):
|
||||
pattern_match = name_pattern.search(lines, 0)
|
||||
while pattern_match is not None:
|
||||
# Scan over the arguments
|
||||
height = 1
|
||||
start = pattern_match.start()
|
||||
end = pattern_match.end()
|
||||
assert lines[end - 1] == '('
|
||||
last_match = end
|
||||
arg_index = [0] # Wrap state into array, to work around Python "scoping"
|
||||
mapping = { }
|
||||
def add_arg(str):
|
||||
# Remember to expand recursively in the arguments
|
||||
replacement = ExpandMacros(str.strip(), macros)
|
||||
mapping[macro.args[arg_index[0]]] = replacement
|
||||
arg_index[0] += 1
|
||||
while end < len(lines) and height > 0:
|
||||
# We don't count commas at higher nesting levels.
|
||||
if lines[end] == ',' and height == 1:
|
||||
add_arg(lines[last_match:end])
|
||||
last_match = end + 1
|
||||
elif lines[end] in ['(', '{', '[']:
|
||||
height = height + 1
|
||||
elif lines[end] in [')', '}', ']']:
|
||||
height = height - 1
|
||||
end = end + 1
|
||||
# Remember to add the last match.
|
||||
add_arg(lines[last_match:end-1])
|
||||
result = macro.expand(mapping)
|
||||
# Replace the occurrence of the macro with the expansion
|
||||
lines = lines[:start] + result + lines[end:]
|
||||
pattern_match = name_pattern.search(lines, start + len(result))
|
||||
return lines
|
||||
|
||||
class TextMacro:
|
||||
def __init__(self, args, body):
|
||||
self.args = args
|
||||
self.body = body
|
||||
def expand(self, mapping):
|
||||
result = self.body
|
||||
for key, value in mapping.items():
|
||||
result = result.replace(key, value)
|
||||
return result
|
||||
|
||||
class PythonMacro:
|
||||
def __init__(self, args, fun):
|
||||
self.args = args
|
||||
self.fun = fun
|
||||
def expand(self, mapping):
|
||||
args = []
|
||||
for arg in self.args:
|
||||
args.append(mapping[arg])
|
||||
return str(self.fun(*args))
|
||||
|
||||
CONST_PATTERN = re.compile(r'^const\s+([a-zA-Z0-9_]+)\s*=\s*([^;]*);$')
|
||||
MACRO_PATTERN = re.compile(r'^macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
|
||||
PYTHON_MACRO_PATTERN = re.compile(r'^python\s+macro\s+([a-zA-Z0-9_]+)\s*\(([^)]*)\)\s*=\s*([^;]*);$')
|
||||
|
||||
|
||||
def ReadMacros(lines):
|
||||
constants = []
|
||||
macros = []
|
||||
for line in lines:
|
||||
hash = line.find('#')
|
||||
if hash != -1: line = line[:hash]
|
||||
line = line.strip()
|
||||
if len(line) is 0: continue
|
||||
const_match = CONST_PATTERN.match(line)
|
||||
if const_match:
|
||||
name = const_match.group(1)
|
||||
value = const_match.group(2).strip()
|
||||
constants.append((re.compile("\\b%s\\b" % name), value))
|
||||
else:
|
||||
macro_match = MACRO_PATTERN.match(line)
|
||||
if macro_match:
|
||||
name = macro_match.group(1)
|
||||
args = [match.strip() for match in macro_match.group(2).split(',')]
|
||||
body = macro_match.group(3).strip()
|
||||
macros.append((re.compile("\\b%s\\(" % name), TextMacro(args, body)))
|
||||
else:
|
||||
python_match = PYTHON_MACRO_PATTERN.match(line)
|
||||
if python_match:
|
||||
name = python_match.group(1)
|
||||
args = [match.strip() for match in python_match.group(2).split(',')]
|
||||
body = python_match.group(3).strip()
|
||||
fun = eval("lambda " + ",".join(args) + ': ' + body)
|
||||
macros.append((re.compile("\\b%s\\(" % name), PythonMacro(args, fun)))
|
||||
else:
|
||||
raise ("Illegal line: " + line)
|
||||
return (constants, macros)
|
||||
|
||||
|
||||
HEADER_TEMPLATE = """\
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
namespace js {
|
||||
namespace selfhosted {
|
||||
static const char sources[] = { %(sources_data)s };
|
||||
|
||||
%(raw_sources_declaration)s\
|
||||
|
||||
uint32_t GetRawScriptsSize() {
|
||||
return %(raw_total_length)i;
|
||||
}
|
||||
} // selfhosted
|
||||
} // js
|
||||
"""
|
||||
|
||||
|
||||
RAW_SOURCES_COMPRESSION_DECLARATION = """\
|
||||
static const char* raw_sources = NULL;
|
||||
"""
|
||||
|
||||
|
||||
RAW_SOURCES_DECLARATION = """\
|
||||
static const char* raw_sources = reinterpret_cast<const char*>(sources);
|
||||
"""
|
||||
|
||||
|
||||
GET_INDEX_CASE = """\
|
||||
if (strcmp(name, "%(id)s") == 0) return %(i)i;
|
||||
"""
|
||||
|
||||
|
||||
GET_RAW_SCRIPT_SOURCE_CASE = """\
|
||||
if (index == %(i)i) return Vector<const char>(raw_sources + %(offset)i, %(raw_length)i);
|
||||
"""
|
||||
|
||||
|
||||
GET_SCRIPT_NAME_CASE = """\
|
||||
if (index == %(i)i) return Vector<const char>("%(name)s", %(length)i);
|
||||
"""
|
||||
|
||||
def JS2C(source, target, env):
|
||||
ids = []
|
||||
debugger_ids = []
|
||||
modules = []
|
||||
# Locate the macros file name.
|
||||
consts = []
|
||||
macros = []
|
||||
for s in source:
|
||||
if 'macros.py' == (os.path.split(str(s))[1]):
|
||||
(consts, macros) = ReadMacros(ReadLines(str(s)))
|
||||
else:
|
||||
modules.append(s)
|
||||
|
||||
minifier = jsmin.JavaScriptMinifier()
|
||||
|
||||
module_offset = 0
|
||||
all_sources = []
|
||||
for module in modules:
|
||||
filename = str(module)
|
||||
debugger = filename.endswith('-debugger.js')
|
||||
lines = ReadFile(filename)
|
||||
lines = ExpandConstants(lines, consts)
|
||||
lines = ExpandMacros(lines, macros)
|
||||
Validate(lines, filename)
|
||||
# FIXME #824112
|
||||
#if not env['DEBUG']:
|
||||
# lines = minifier.JSMinify(lines)
|
||||
id = (os.path.split(filename)[1])[:-3]
|
||||
if debugger: id = id[:-9]
|
||||
raw_length = len(lines)
|
||||
if debugger:
|
||||
debugger_ids.append((id, raw_length, module_offset))
|
||||
else:
|
||||
ids.append((id, raw_length, module_offset))
|
||||
all_sources.append(lines)
|
||||
module_offset += raw_length
|
||||
total_length = raw_total_length = module_offset
|
||||
|
||||
if env['COMPRESSION'] == 'off':
|
||||
raw_sources_declaration = RAW_SOURCES_DECLARATION
|
||||
sources_data = ToCAsciiArray("".join(all_sources))
|
||||
else:
|
||||
raw_sources_declaration = RAW_SOURCES_COMPRESSION_DECLARATION
|
||||
if env['COMPRESSION'] == 'bz2':
|
||||
all_sources = bz2.compress("".join(all_sources))
|
||||
total_length = len(all_sources)
|
||||
sources_data = ToCArray(all_sources)
|
||||
|
||||
# Build debugger support functions
|
||||
get_index_cases = [ ]
|
||||
get_raw_script_source_cases = [ ]
|
||||
get_script_name_cases = [ ]
|
||||
|
||||
i = 0
|
||||
for (id, raw_length, module_offset) in debugger_ids + ids:
|
||||
native_name = "native %s.js" % id
|
||||
get_index_cases.append(GET_INDEX_CASE % { 'id': id, 'i': i })
|
||||
get_raw_script_source_cases.append(GET_RAW_SCRIPT_SOURCE_CASE % {
|
||||
'offset': module_offset,
|
||||
'raw_length': raw_length,
|
||||
'i': i
|
||||
})
|
||||
get_script_name_cases.append(GET_SCRIPT_NAME_CASE % {
|
||||
'name': native_name,
|
||||
'length': len(native_name),
|
||||
'i': i
|
||||
})
|
||||
i = i + 1
|
||||
|
||||
# Emit result
|
||||
output = open(str(target[0]), "w")
|
||||
output.write(HEADER_TEMPLATE % {
|
||||
'builtin_count': len(ids) + len(debugger_ids),
|
||||
'debugger_count': len(debugger_ids),
|
||||
'sources_data': sources_data,
|
||||
'raw_sources_declaration': raw_sources_declaration,
|
||||
'raw_total_length': raw_total_length,
|
||||
'total_length': total_length,
|
||||
'get_index_cases': "".join(get_index_cases),
|
||||
'get_raw_script_source_cases': "".join(get_raw_script_source_cases),
|
||||
'get_script_name_cases': "".join(get_script_name_cases),
|
||||
'type': env['TYPE']
|
||||
})
|
||||
output.close()
|
||||
return "".join(all_sources)
|
||||
|
||||
def main():
|
||||
natives = sys.argv[1]
|
||||
type = sys.argv[2]
|
||||
compression = sys.argv[3]
|
||||
source_files = sys.argv[4:]
|
||||
JS2C(source_files, [natives], { 'TYPE': type, 'COMPRESSION': compression })
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,282 +0,0 @@
|
||||
#!/usr/bin/python2.4
|
||||
|
||||
# Copyright 2012 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
"""A JavaScript minifier.
|
||||
|
||||
It is far from being a complete JS parser, so there are many valid
|
||||
JavaScript programs that will be ruined by it. Another strangeness is that
|
||||
it accepts $ and % as parts of identifiers. It doesn't merge lines or strip
|
||||
out blank lines in order to ease debugging. Variables at the top scope are
|
||||
properties of the global object so we can't rename them. It is assumed that
|
||||
you introduce variables with var as if JavaScript followed C++ scope rules
|
||||
around curly braces, so the declaration must be above the first use.
|
||||
|
||||
Use as:
|
||||
import jsmin
|
||||
minifier = JavaScriptMinifier()
|
||||
program1 = minifier.JSMinify(program1)
|
||||
program2 = minifier.JSMinify(program2)
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
|
||||
class JavaScriptMinifier(object):
|
||||
"""An object that you can feed code snippets to to get them minified."""
|
||||
|
||||
def __init__(self):
|
||||
# We prepopulate the list of identifiers that shouldn't be used. These
|
||||
# short language keywords could otherwise be used by the script as variable
|
||||
# names.
|
||||
self.seen_identifiers = {"do": True, "in": True}
|
||||
self.identifier_counter = 0
|
||||
self.in_comment = False
|
||||
self.map = {}
|
||||
self.nesting = 0
|
||||
|
||||
def LookAtIdentifier(self, m):
|
||||
"""Records identifiers or keywords that we see in use.
|
||||
|
||||
(So we can avoid renaming variables to these strings.)
|
||||
Args:
|
||||
m: The match object returned by re.search.
|
||||
|
||||
Returns:
|
||||
Nothing.
|
||||
"""
|
||||
identifier = m.group(1)
|
||||
self.seen_identifiers[identifier] = True
|
||||
|
||||
def Push(self):
|
||||
"""Called when we encounter a '{'."""
|
||||
self.nesting += 1
|
||||
|
||||
def Pop(self):
|
||||
"""Called when we encounter a '}'."""
|
||||
self.nesting -= 1
|
||||
# We treat each top-level opening brace as a single scope that can span
|
||||
# several sets of nested braces.
|
||||
if self.nesting == 0:
|
||||
self.map = {}
|
||||
self.identifier_counter = 0
|
||||
|
||||
def Declaration(self, m):
|
||||
"""Rewrites bits of the program selected by a regexp.
|
||||
|
||||
These can be curly braces, literal strings, function declarations and var
|
||||
declarations. (These last two must be on one line including the opening
|
||||
curly brace of the function for their variables to be renamed).
|
||||
|
||||
Args:
|
||||
m: The match object returned by re.search.
|
||||
|
||||
Returns:
|
||||
The string that should replace the match in the rewritten program.
|
||||
"""
|
||||
matched_text = m.group(0)
|
||||
if matched_text == "{":
|
||||
self.Push()
|
||||
return matched_text
|
||||
if matched_text == "}":
|
||||
self.Pop()
|
||||
return matched_text
|
||||
if re.match("[\"'/]", matched_text):
|
||||
return matched_text
|
||||
m = re.match(r"var ", matched_text)
|
||||
if m:
|
||||
var_names = matched_text[m.end():]
|
||||
var_names = re.split(r",", var_names)
|
||||
return "var " + ",".join(map(self.FindNewName, var_names))
|
||||
m = re.match(r"(function\b[^(]*)\((.*)\)\{$", matched_text)
|
||||
if m:
|
||||
up_to_args = m.group(1)
|
||||
args = m.group(2)
|
||||
args = re.split(r",", args)
|
||||
self.Push()
|
||||
return up_to_args + "(" + ",".join(map(self.FindNewName, args)) + "){"
|
||||
|
||||
if matched_text in self.map:
|
||||
return self.map[matched_text]
|
||||
|
||||
return matched_text
|
||||
|
||||
def CharFromNumber(self, number):
|
||||
"""A single-digit base-52 encoding using a-zA-Z."""
|
||||
if number < 26:
|
||||
return chr(number + 97)
|
||||
number -= 26
|
||||
return chr(number + 65)
|
||||
|
||||
def FindNewName(self, var_name):
|
||||
"""Finds a new 1-character or 2-character name for a variable.
|
||||
|
||||
Enters it into the mapping table for this scope.
|
||||
|
||||
Args:
|
||||
var_name: The name of the variable before renaming.
|
||||
|
||||
Returns:
|
||||
The new name of the variable.
|
||||
"""
|
||||
new_identifier = ""
|
||||
# Variable names that end in _ are member variables of the global object,
|
||||
# so they can be visible from code in a different scope. We leave them
|
||||
# alone.
|
||||
if var_name in self.map:
|
||||
return self.map[var_name]
|
||||
if self.nesting == 0:
|
||||
return var_name
|
||||
while True:
|
||||
identifier_first_char = self.identifier_counter % 52
|
||||
identifier_second_char = self.identifier_counter // 52
|
||||
new_identifier = self.CharFromNumber(identifier_first_char)
|
||||
if identifier_second_char != 0:
|
||||
new_identifier = (
|
||||
self.CharFromNumber(identifier_second_char - 1) + new_identifier)
|
||||
self.identifier_counter += 1
|
||||
if not new_identifier in self.seen_identifiers:
|
||||
break
|
||||
|
||||
self.map[var_name] = new_identifier
|
||||
return new_identifier
|
||||
|
||||
def RemoveSpaces(self, m):
|
||||
"""Returns literal strings unchanged, replaces other inputs with group 2.
|
||||
|
||||
Other inputs are replaced with the contents of capture 1. This is either
|
||||
a single space or an empty string.
|
||||
|
||||
Args:
|
||||
m: The match object returned by re.search.
|
||||
|
||||
Returns:
|
||||
The string that should be inserted instead of the matched text.
|
||||
"""
|
||||
entire_match = m.group(0)
|
||||
replacement = m.group(1)
|
||||
if re.match(r"'.*'$", entire_match):
|
||||
return entire_match
|
||||
if re.match(r'".*"$', entire_match):
|
||||
return entire_match
|
||||
if re.match(r"/.+/$", entire_match):
|
||||
return entire_match
|
||||
return replacement
|
||||
|
||||
def JSMinify(self, text):
|
||||
"""The main entry point. Takes a text and returns a compressed version.
|
||||
|
||||
The compressed version hopefully does the same thing. Line breaks are
|
||||
preserved.
|
||||
|
||||
Args:
|
||||
text: The text of the code snippet as a multiline string.
|
||||
|
||||
Returns:
|
||||
The compressed text of the code snippet as a multiline string.
|
||||
"""
|
||||
new_lines = []
|
||||
for line in re.split(r"\n", text):
|
||||
line = line.replace("\t", " ")
|
||||
if self.in_comment:
|
||||
m = re.search(r"\*/", line)
|
||||
if m:
|
||||
line = line[m.end():]
|
||||
self.in_comment = False
|
||||
else:
|
||||
new_lines.append("")
|
||||
continue
|
||||
|
||||
if not self.in_comment:
|
||||
line = re.sub(r"/\*.*?\*/", " ", line)
|
||||
line = re.sub(r"//.*", "", line)
|
||||
m = re.search(r"/\*", line)
|
||||
if m:
|
||||
line = line[:m.start()]
|
||||
self.in_comment = True
|
||||
|
||||
# Strip leading and trailing spaces.
|
||||
line = re.sub(r"^ +", "", line)
|
||||
line = re.sub(r" +$", "", line)
|
||||
# A regexp that matches a literal string surrounded by "double quotes".
|
||||
# This regexp can handle embedded backslash-escaped characters including
|
||||
# embedded backslash-escaped double quotes.
|
||||
double_quoted_string = r'"(?:[^"\\]|\\.)*"'
|
||||
# A regexp that matches a literal string surrounded by 'double quotes'.
|
||||
single_quoted_string = r"'(?:[^'\\]|\\.)*'"
|
||||
# A regexp that matches a regexp literal surrounded by /slashes/.
|
||||
# Don't allow a regexp to have a ) before the first ( since that's a
|
||||
# syntax error and it's probably just two unrelated slashes.
|
||||
# Also don't allow it to come after anything that can only be the
|
||||
# end of a primary expression.
|
||||
slash_quoted_regexp = r"(?<![\w$'\")\]])/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\([^/\\]|\\.)*/"
|
||||
# Replace multiple spaces with a single space.
|
||||
line = re.sub("|".join([double_quoted_string,
|
||||
single_quoted_string,
|
||||
slash_quoted_regexp,
|
||||
"( )+"]),
|
||||
self.RemoveSpaces,
|
||||
line)
|
||||
# Strip single spaces unless they have an identifier character both before
|
||||
# and after the space. % and $ are counted as identifier characters.
|
||||
line = re.sub("|".join([double_quoted_string,
|
||||
single_quoted_string,
|
||||
slash_quoted_regexp,
|
||||
r"(?<![a-zA-Z_0-9$%]) | (?![a-zA-Z_0-9$%])()"]),
|
||||
self.RemoveSpaces,
|
||||
line)
|
||||
# Collect keywords and identifiers that are already in use.
|
||||
if self.nesting == 0:
|
||||
re.sub(r"([a-zA-Z0-9_$%]+)", self.LookAtIdentifier, line)
|
||||
function_declaration_regexp = (
|
||||
r"\bfunction" # Function definition keyword...
|
||||
r"( [\w$%]+)?" # ...optional function name...
|
||||
r"\([\w$%,]+\)\{") # ...argument declarations.
|
||||
# Unfortunately the keyword-value syntax { key:value } makes the key look
|
||||
# like a variable where in fact it is a literal string. We use the
|
||||
# presence or absence of a question mark to try to distinguish between
|
||||
# this case and the ternary operator: "condition ? iftrue : iffalse".
|
||||
if re.search(r"\?", line):
|
||||
block_trailing_colon = r""
|
||||
else:
|
||||
block_trailing_colon = r"(?![:\w$%])"
|
||||
# Variable use. Cannot follow a period precede a colon.
|
||||
variable_use_regexp = r"(?<![.\w$%])[\w$%]+" + block_trailing_colon
|
||||
line = re.sub("|".join([double_quoted_string,
|
||||
single_quoted_string,
|
||||
slash_quoted_regexp,
|
||||
r"\{", # Curly braces.
|
||||
r"\}",
|
||||
r"\bvar [\w$%,]+", # var declarations.
|
||||
function_declaration_regexp,
|
||||
variable_use_regexp]),
|
||||
self.Declaration,
|
||||
line)
|
||||
new_lines.append(line)
|
||||
|
||||
return "\n".join(new_lines) + "\n"
|
@ -1,259 +0,0 @@
|
||||
# Copyright 2006-2009 the V8 project authors. All rights reserved.
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following
|
||||
# disclaimer in the documentation and/or other materials provided
|
||||
# with the distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived
|
||||
# from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Dictionary that is passed as defines for js2c.py.
|
||||
# Used for defines that must be defined for all native JS files.
|
||||
|
||||
const NONE = 0;
|
||||
const READ_ONLY = 1;
|
||||
const DONT_ENUM = 2;
|
||||
const DONT_DELETE = 4;
|
||||
|
||||
# Constants used for getter and setter operations.
|
||||
const GETTER = 0;
|
||||
const SETTER = 1;
|
||||
|
||||
# These definitions must match the index of the properties in objects.h.
|
||||
const kApiTagOffset = 0;
|
||||
const kApiPropertyListOffset = 1;
|
||||
const kApiSerialNumberOffset = 2;
|
||||
const kApiConstructorOffset = 2;
|
||||
const kApiPrototypeTemplateOffset = 5;
|
||||
const kApiParentTemplateOffset = 6;
|
||||
const kApiFlagOffset = 14;
|
||||
|
||||
const NO_HINT = 0;
|
||||
const NUMBER_HINT = 1;
|
||||
const STRING_HINT = 2;
|
||||
|
||||
const kFunctionTag = 0;
|
||||
const kNewObjectTag = 1;
|
||||
|
||||
# For date.js.
|
||||
const HoursPerDay = 24;
|
||||
const MinutesPerHour = 60;
|
||||
const SecondsPerMinute = 60;
|
||||
const msPerSecond = 1000;
|
||||
const msPerMinute = 60000;
|
||||
const msPerHour = 3600000;
|
||||
const msPerDay = 86400000;
|
||||
const msPerMonth = 2592000000;
|
||||
|
||||
# For apinatives.js
|
||||
const kUninitialized = -1;
|
||||
const kReadOnlyPrototypeBit = 3; # For FunctionTemplateInfo, matches objects.h
|
||||
|
||||
# Note: kDayZeroInJulianDay = ToJulianDay(1970, 0, 1).
|
||||
const kInvalidDate = 'Invalid Date';
|
||||
const kDayZeroInJulianDay = 2440588;
|
||||
const kMonthMask = 0x1e0;
|
||||
const kDayMask = 0x01f;
|
||||
const kYearShift = 9;
|
||||
const kMonthShift = 5;
|
||||
|
||||
# Limits for parts of the date, so that we support all the dates that
|
||||
# ECMA 262 - 15.9.1.1 requires us to, but at the same time be sure that
|
||||
# the date (days since 1970) is in SMI range.
|
||||
const kMinYear = -1000000;
|
||||
const kMaxYear = 1000000;
|
||||
const kMinMonth = -10000000;
|
||||
const kMaxMonth = 10000000;
|
||||
|
||||
# Native cache ids.
|
||||
const STRING_TO_REGEXP_CACHE_ID = 0;
|
||||
|
||||
# Type query macros.
|
||||
#
|
||||
# Note: We have special support for typeof(foo) === 'bar' in the compiler.
|
||||
# It will *not* generate a runtime typeof call for the most important
|
||||
# values of 'bar'.
|
||||
macro IS_NULL(arg) = (arg === null);
|
||||
macro IS_NULL_OR_UNDEFINED(arg) = (arg == null);
|
||||
macro IS_UNDEFINED(arg) = (typeof(arg) === 'undefined');
|
||||
macro IS_NUMBER(arg) = (typeof(arg) === 'number');
|
||||
macro IS_STRING(arg) = (typeof(arg) === 'string');
|
||||
macro IS_BOOLEAN(arg) = (typeof(arg) === 'boolean');
|
||||
macro IS_OBJECT(arg) = (%_IsObject(arg));
|
||||
macro IS_ARRAY(arg) = (%_IsArray(arg));
|
||||
macro IS_FUNCTION(arg) = (%_IsFunction(arg));
|
||||
macro IS_REGEXP(arg) = (%_IsRegExp(arg));
|
||||
macro IS_SET(arg) = (%_ClassOf(arg) === 'Set');
|
||||
macro IS_MAP(arg) = (%_ClassOf(arg) === 'Map');
|
||||
macro IS_WEAKMAP(arg) = (%_ClassOf(arg) === 'WeakMap');
|
||||
macro IS_DATE(arg) = (%_ClassOf(arg) === 'Date');
|
||||
macro IS_NUMBER_WRAPPER(arg) = (%_ClassOf(arg) === 'Number');
|
||||
macro IS_STRING_WRAPPER(arg) = (%_ClassOf(arg) === 'String');
|
||||
macro IS_BOOLEAN_WRAPPER(arg) = (%_ClassOf(arg) === 'Boolean');
|
||||
macro IS_ERROR(arg) = (%_ClassOf(arg) === 'Error');
|
||||
macro IS_SCRIPT(arg) = (%_ClassOf(arg) === 'Script');
|
||||
macro IS_ARGUMENTS(arg) = (%_ClassOf(arg) === 'Arguments');
|
||||
macro IS_GLOBAL(arg) = (%_ClassOf(arg) === 'global');
|
||||
macro IS_UNDETECTABLE(arg) = (%_IsUndetectableObject(arg));
|
||||
macro FLOOR(arg) = $floor(arg);
|
||||
|
||||
# Macro for ECMAScript 5 queries of the type:
|
||||
# "Type(O) is object."
|
||||
# This is the same as being either a function or an object in V8 terminology
|
||||
# (including proxies).
|
||||
# In addition, an undetectable object is also included by this.
|
||||
macro IS_SPEC_OBJECT(arg) = (%_IsSpecObject(arg));
|
||||
|
||||
# Macro for ECMAScript 5 queries of the type:
|
||||
# "IsCallable(O)"
|
||||
# We assume here that this is the same as being either a function or a function
|
||||
# proxy. That ignores host objects with [[Call]] methods, but in most situations
|
||||
# we cannot handle those anyway.
|
||||
macro IS_SPEC_FUNCTION(arg) = (%_ClassOf(arg) === 'Function');
|
||||
|
||||
# Indices in bound function info retrieved by %BoundFunctionGetBindings(...).
|
||||
const kBoundFunctionIndex = 0;
|
||||
const kBoundThisIndex = 1;
|
||||
const kBoundArgumentsStartIndex = 2;
|
||||
|
||||
# Inline macros. Use %IS_VAR to make sure arg is evaluated only once.
|
||||
macro NUMBER_IS_NAN(arg) = (!%_IsSmi(%IS_VAR(arg)) && !(arg == arg));
|
||||
macro NUMBER_IS_FINITE(arg) = (%_IsSmi(%IS_VAR(arg)) || ((arg == arg) && (arg != 1/0) && (arg != -1/0)));
|
||||
macro TO_INTEGER(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToInteger(ToNumber(arg)));
|
||||
macro TO_INTEGER_MAP_MINUS_ZERO(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : %NumberToIntegerMapMinusZero(ToNumber(arg)));
|
||||
macro TO_INT32(arg) = (%_IsSmi(%IS_VAR(arg)) ? arg : (arg >> 0));
|
||||
macro TO_UINT32(arg) = (arg >>> 0);
|
||||
macro TO_STRING_INLINE(arg) = (IS_STRING(%IS_VAR(arg)) ? arg : NonStringToString(arg));
|
||||
macro TO_NUMBER_INLINE(arg) = (IS_NUMBER(%IS_VAR(arg)) ? arg : NonNumberToNumber(arg));
|
||||
macro TO_OBJECT_INLINE(arg) = (IS_SPEC_OBJECT(%IS_VAR(arg)) ? arg : ToObject(arg));
|
||||
macro JSON_NUMBER_TO_STRING(arg) = ((%_IsSmi(%IS_VAR(arg)) || arg - arg == 0) ? %_NumberToString(arg) : "null");
|
||||
|
||||
# Macros implemented in Python.
|
||||
python macro CHAR_CODE(str) = ord(str[1]);
|
||||
|
||||
# Constants used on an array to implement the properties of the RegExp object.
|
||||
const REGEXP_NUMBER_OF_CAPTURES = 0;
|
||||
const REGEXP_FIRST_CAPTURE = 3;
|
||||
|
||||
# We can't put macros in macros so we use constants here.
|
||||
# REGEXP_NUMBER_OF_CAPTURES
|
||||
macro NUMBER_OF_CAPTURES(array) = ((array)[0]);
|
||||
|
||||
# Limit according to ECMA 262 15.9.1.1
|
||||
const MAX_TIME_MS = 8640000000000000;
|
||||
# Limit which is MAX_TIME_MS + msPerMonth.
|
||||
const MAX_TIME_BEFORE_UTC = 8640002592000000;
|
||||
|
||||
# Gets the value of a Date object. If arg is not a Date object
|
||||
# a type error is thrown.
|
||||
macro CHECK_DATE(arg) = if (%_ClassOf(arg) !== 'Date') ThrowDateTypeError();
|
||||
macro LOCAL_DATE_VALUE(arg) = (%_DateField(arg, 0) + %_DateField(arg, 21));
|
||||
macro UTC_DATE_VALUE(arg) = (%_DateField(arg, 0));
|
||||
|
||||
macro LOCAL_YEAR(arg) = (%_DateField(arg, 1));
|
||||
macro LOCAL_MONTH(arg) = (%_DateField(arg, 2));
|
||||
macro LOCAL_DAY(arg) = (%_DateField(arg, 3));
|
||||
macro LOCAL_WEEKDAY(arg) = (%_DateField(arg, 4));
|
||||
macro LOCAL_HOUR(arg) = (%_DateField(arg, 5));
|
||||
macro LOCAL_MIN(arg) = (%_DateField(arg, 6));
|
||||
macro LOCAL_SEC(arg) = (%_DateField(arg, 7));
|
||||
macro LOCAL_MS(arg) = (%_DateField(arg, 8));
|
||||
macro LOCAL_DAYS(arg) = (%_DateField(arg, 9));
|
||||
macro LOCAL_TIME_IN_DAY(arg) = (%_DateField(arg, 10));
|
||||
|
||||
macro UTC_YEAR(arg) = (%_DateField(arg, 11));
|
||||
macro UTC_MONTH(arg) = (%_DateField(arg, 12));
|
||||
macro UTC_DAY(arg) = (%_DateField(arg, 13));
|
||||
macro UTC_WEEKDAY(arg) = (%_DateField(arg, 14));
|
||||
macro UTC_HOUR(arg) = (%_DateField(arg, 15));
|
||||
macro UTC_MIN(arg) = (%_DateField(arg, 16));
|
||||
macro UTC_SEC(arg) = (%_DateField(arg, 17));
|
||||
macro UTC_MS(arg) = (%_DateField(arg, 18));
|
||||
macro UTC_DAYS(arg) = (%_DateField(arg, 19));
|
||||
macro UTC_TIME_IN_DAY(arg) = (%_DateField(arg, 20));
|
||||
|
||||
macro TIMEZONE_OFFSET(arg) = (%_DateField(arg, 21));
|
||||
|
||||
macro SET_UTC_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 1));
|
||||
macro SET_LOCAL_DATE_VALUE(arg, value) = (%DateSetValue(arg, value, 0));
|
||||
|
||||
# Last input and last subject of regexp matches.
|
||||
const LAST_SUBJECT_INDEX = 1;
|
||||
macro LAST_SUBJECT(array) = ((array)[1]);
|
||||
macro LAST_INPUT(array) = ((array)[2]);
|
||||
|
||||
# REGEXP_FIRST_CAPTURE
|
||||
macro CAPTURE(index) = (3 + (index));
|
||||
const CAPTURE0 = 3;
|
||||
const CAPTURE1 = 4;
|
||||
|
||||
# For the regexp capture override array. This has the same
|
||||
# format as the arguments to a function called from
|
||||
# String.prototype.replace.
|
||||
macro OVERRIDE_MATCH(override) = ((override)[0]);
|
||||
macro OVERRIDE_POS(override) = ((override)[(override).length - 2]);
|
||||
macro OVERRIDE_SUBJECT(override) = ((override)[(override).length - 1]);
|
||||
# 1-based so index of 1 returns the first capture
|
||||
macro OVERRIDE_CAPTURE(override, index) = ((override)[(index)]);
|
||||
|
||||
# The mode asserts options object for ParallelArray
|
||||
macro TRY_PARALLEL(MODE) = ((!MODE || MODE.mode === "par"));
|
||||
macro ASSERT_SEQUENTIAL_IS_OK(MODE) = do { if (MODE) AssertSequentialIsOK(MODE) } while(false);
|
||||
|
||||
# How many items at a time do we do recomp. for parallel execution.
|
||||
# Note that filter currently assumes that this is no greater than 32
|
||||
# in order to make use of a bitset.
|
||||
const CHUNK_SHIFT = 5;
|
||||
const CHUNK_SIZE = 32;
|
||||
|
||||
# Slice array: see ComputeAllSliceBounds() in ParallelArray.js
|
||||
macro SLICE_INFO(START, END) = START, END, START, 0;
|
||||
macro SLICE_START(ID) = ((ID << 2) + 0);
|
||||
macro SLICE_END(ID) = ((ID << 2) + 1);
|
||||
macro SLICE_POS(ID) = ((ID << 2) + 2);
|
||||
|
||||
# Safe version of ARRAY.push(ELEMENT)
|
||||
macro ARRAY_PUSH(ARRAY, ELEMENT) = callFunction(std_Array_push, ARRAY, ELEMENT);
|
||||
macro ARRAY_SLICE(ARRAY, ELEMENT) = callFunction(std_Array_slice, ARRAY, ELEMENT);
|
||||
|
||||
# PropertyDescriptor return value indices - must match
|
||||
# PropertyDescriptorIndices in runtime.cc.
|
||||
const IS_ACCESSOR_INDEX = 0;
|
||||
const VALUE_INDEX = 1;
|
||||
const GETTER_INDEX = 2;
|
||||
const SETTER_INDEX = 3;
|
||||
const WRITABLE_INDEX = 4;
|
||||
const ENUMERABLE_INDEX = 5;
|
||||
const CONFIGURABLE_INDEX = 6;
|
||||
|
||||
# For messages.js
|
||||
# Matches Script::Type from objects.h
|
||||
const TYPE_NATIVE = 0;
|
||||
const TYPE_EXTENSION = 1;
|
||||
const TYPE_NORMAL = 2;
|
||||
|
||||
# Matches Script::CompilationType from objects.h
|
||||
const COMPILATION_TYPE_HOST = 0;
|
||||
const COMPILATION_TYPE_EVAL = 1;
|
||||
const COMPILATION_TYPE_JSON = 2;
|
||||
|
||||
# Matches Messages::kNoLineNumberInfo from v8.h
|
||||
const kNoLineNumberInfo = 0;
|
@ -27,6 +27,8 @@ using mozilla::DebugOnly;
|
||||
|
||||
void * const js::NullPtr::constNullValue = NULL;
|
||||
|
||||
JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = NULL;
|
||||
|
||||
/*
|
||||
* There are two mostly separate mark paths. The first is a fast path used
|
||||
* internally in the GC. The second is a slow path used for root marking and
|
||||
|
@ -4484,7 +4484,7 @@ CodeGenerator::link()
|
||||
JSContext *cx = GetIonContext()->cx;
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *code = linker.newCode(cx);
|
||||
IonCode *code = linker.newCode(cx, JSC::ION_CODE);
|
||||
if (!code)
|
||||
return false;
|
||||
|
||||
|
@ -97,7 +97,7 @@ IonCache::LinkStatus
|
||||
IonCache::linkCode(JSContext *cx, MacroAssembler &masm, IonScript *ion, IonCode **code)
|
||||
{
|
||||
Linker linker(masm);
|
||||
*code = linker.newCode(cx);
|
||||
*code = linker.newCode(cx, JSC::ION_CODE);
|
||||
if (!code)
|
||||
return LINK_ERROR;
|
||||
|
||||
|
@ -29,7 +29,10 @@ class Linker
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IonCode *newCode(JSContext *cx, IonCompartment *comp) {
|
||||
IonCode *newCode(JSContext *cx, IonCompartment *comp, JSC::CodeKind kind) {
|
||||
JS_ASSERT(kind == JSC::ION_CODE ||
|
||||
kind == JSC::BASELINE_CODE ||
|
||||
kind == JSC::OTHER_CODE);
|
||||
gc::AutoSuppressGC suppressGC(cx);
|
||||
if (masm.oom())
|
||||
return fail(cx);
|
||||
@ -39,7 +42,7 @@ class Linker
|
||||
if (bytesNeeded >= MAX_BUFFER_SIZE)
|
||||
return fail(cx);
|
||||
|
||||
uint8_t *result = (uint8_t *)comp->execAlloc()->alloc(bytesNeeded, &pool, JSC::ION_CODE);
|
||||
uint8_t *result = (uint8_t *)comp->execAlloc()->alloc(bytesNeeded, &pool, kind);
|
||||
if (!result)
|
||||
return fail(cx);
|
||||
|
||||
@ -67,8 +70,8 @@ class Linker
|
||||
masm.finish();
|
||||
}
|
||||
|
||||
IonCode *newCode(JSContext *cx) {
|
||||
return newCode(cx, cx->compartment->ionCompartment());
|
||||
IonCode *newCode(JSContext *cx, JSC::CodeKind kind) {
|
||||
return newCode(cx, cx->compartment->ionCompartment(), kind);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -196,7 +196,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
|
||||
GenerateReturn(masm, JS_TRUE);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -242,7 +242,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
|
||||
masm.ma_add(sp, r1, sp);
|
||||
masm.generateBailoutTail(r1);
|
||||
Linker linker(masm);
|
||||
IonCode *code = linker.newCode(cx);
|
||||
IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw());
|
||||
return code;
|
||||
}
|
||||
@ -339,7 +339,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
|
||||
|
||||
masm.ret();
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -447,7 +447,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
|
||||
GenerateBailoutThunk(masm, frameClass);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -457,7 +457,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
|
||||
GenerateBailoutThunk(masm, NO_FRAME_SIZE_CLASS_ID);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -596,7 +596,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.handleException();
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
if (!wrapper)
|
||||
return NULL;
|
||||
|
||||
@ -634,6 +634,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -218,7 +218,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
|
||||
masm.generateBailoutTail(rdx);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -304,7 +304,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -359,7 +359,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
|
||||
GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -504,7 +504,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.handleException();
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
if (!wrapper)
|
||||
return NULL;
|
||||
|
||||
@ -542,6 +542,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ IonRuntime::generateEnterJIT(JSContext *cx)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -205,7 +205,7 @@ IonRuntime::generateInvalidator(JSContext *cx)
|
||||
masm.generateBailoutTail(edx);
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *code = linker.newCode(cx);
|
||||
IonCode *code = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
IonSpew(IonSpew_Invalidate, " invalidation thunk created at %p", (void *) code->raw());
|
||||
return code;
|
||||
}
|
||||
@ -301,7 +301,7 @@ IonRuntime::generateArgumentsRectifier(JSContext *cx)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -369,7 +369,7 @@ IonRuntime::generateBailoutTable(JSContext *cx, uint32_t frameClass)
|
||||
GenerateBailoutThunk(cx, masm, frameClass);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -380,7 +380,7 @@ IonRuntime::generateBailoutHandler(JSContext *cx)
|
||||
GenerateBailoutThunk(cx, masm, NO_FRAME_SIZE_CLASS_ID);
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
IonCode *
|
||||
@ -530,7 +530,7 @@ IonRuntime::generateVMWrapper(JSContext *cx, const VMFunction &f)
|
||||
masm.handleException();
|
||||
|
||||
Linker linker(masm);
|
||||
IonCode *wrapper = linker.newCode(cx);
|
||||
IonCode *wrapper = linker.newCode(cx, JSC::OTHER_CODE);
|
||||
if (!wrapper)
|
||||
return NULL;
|
||||
|
||||
@ -569,6 +569,6 @@ IonRuntime::generatePreBarrier(JSContext *cx, MIRType type)
|
||||
masm.ret();
|
||||
|
||||
Linker linker(masm);
|
||||
return linker.newCode(cx);
|
||||
return linker.newCode(cx, JSC::OTHER_CODE);
|
||||
}
|
||||
|
||||
|
@ -5028,8 +5028,6 @@ using JS::MutableHandleString;
|
||||
using JS::MutableHandleId;
|
||||
using JS::MutableHandleValue;
|
||||
|
||||
using JS::NullPtr; /* To be removed by bug 781070. */
|
||||
|
||||
using JS::Zone;
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -124,16 +124,9 @@ JSRuntime::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, JS::RuntimeSizes
|
||||
|
||||
rtSizes->temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
if (execAlloc_) {
|
||||
execAlloc_->sizeOfCode(&rtSizes->jaegerCode, &rtSizes->ionCode, &rtSizes->asmJSCode,
|
||||
&rtSizes->regexpCode, &rtSizes->unusedCode);
|
||||
} else {
|
||||
rtSizes->jaegerCode = 0;
|
||||
rtSizes->ionCode = 0;
|
||||
rtSizes->asmJSCode = 0;
|
||||
rtSizes->regexpCode = 0;
|
||||
rtSizes->unusedCode = 0;
|
||||
}
|
||||
rtSizes->code = JS::CodeSizes();
|
||||
if (execAlloc_)
|
||||
execAlloc_->sizeOfCode(&rtSizes->code);
|
||||
|
||||
rtSizes->regexpData = bumpAlloc_ ? bumpAlloc_->sizeOfNonHeapData() : 0;
|
||||
|
||||
@ -154,9 +147,10 @@ JSRuntime::sizeOfExplicitNonHeap()
|
||||
size_t n = stackSpace.sizeOf();
|
||||
|
||||
if (execAlloc_) {
|
||||
size_t jaegerCode, ionCode, asmJSCode, regexpCode, unusedCode;
|
||||
execAlloc_->sizeOfCode(&jaegerCode, &ionCode, &asmJSCode, ®expCode, &unusedCode);
|
||||
n += jaegerCode + ionCode + asmJSCode + regexpCode + unusedCode;
|
||||
JS::CodeSizes sizes;
|
||||
execAlloc_->sizeOfCode(&sizes);
|
||||
n += sizes.jaeger + sizes.ion + sizes.baseline + sizes.asmJS +
|
||||
sizes.regexp + sizes.other + sizes.unused;
|
||||
}
|
||||
|
||||
if (bumpAlloc_)
|
||||
|
@ -263,7 +263,7 @@ struct JSCompartment
|
||||
/* Mark cross-compartment wrappers. */
|
||||
void markCrossCompartmentWrappers(JSTracer *trc);
|
||||
|
||||
bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = JS::NullPtr());
|
||||
bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = js::NullPtr());
|
||||
bool wrap(JSContext *cx, JSString **strp);
|
||||
bool wrap(JSContext *cx, js::HeapPtrString *strp);
|
||||
bool wrap(JSContext *cx, JSObject **objp, JSObject *existing = NULL);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "selfhosted.out.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::selfhosted;
|
||||
|
||||
static void
|
||||
selfHosting_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
||||
@ -517,8 +518,21 @@ JSRuntime::initSelfHosting(JSContext *cx)
|
||||
if (script)
|
||||
ok = Execute(cx, script, *shg.get(), &rv);
|
||||
} else {
|
||||
const char *src = selfhosted::raw_sources;
|
||||
uint32_t srcLen = selfhosted::GetRawScriptsSize();
|
||||
uint32_t srcLen = GetRawScriptsSize();
|
||||
|
||||
#ifdef USE_ZLIB
|
||||
const unsigned char *compressed = compressedSources;
|
||||
uint32_t compressedLen = GetCompressedSize();
|
||||
ScopedJSFreePtr<char> src(reinterpret_cast<char *>(cx->malloc_(srcLen)));
|
||||
if (!src || !DecompressString(compressed, compressedLen,
|
||||
reinterpret_cast<unsigned char *>(src.get()), srcLen))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
const char *src = rawSources;
|
||||
#endif
|
||||
|
||||
ok = Evaluate(cx, shg, options, src, srcLen, &rv);
|
||||
}
|
||||
JS_SetErrorReporter(cx, oldReporter);
|
||||
|
@ -1950,28 +1950,35 @@ ReportJSRuntimeExplicitTreeStats(const JS::RuntimeStats &rtStats,
|
||||
"Memory held transiently in JSRuntime and used during "
|
||||
"compilation. It mostly holds parse nodes.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/jaeger-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.jaegerCode,
|
||||
"Memory used by the JaegerMonkey JIT to hold the runtime's "
|
||||
"generated code.");
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/jaeger"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.jaeger,
|
||||
"Memory used by the JaegerMonkey JIT to hold generated code.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/ion-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.ionCode,
|
||||
"Memory used by the IonMonkey JIT to hold the runtime's "
|
||||
"generated code.");
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/ion"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.ion,
|
||||
"Memory used by the IonMonkey JIT to hold generated code.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/asm.js-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.asmJSCode,
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/baseline"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.baseline,
|
||||
"Memory used by the Baseline JIT to hold generated code.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/asm.js"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.asmJS,
|
||||
"Memory used by AOT-compiled asm.js code.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpCode,
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/regexp"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.regexp,
|
||||
"Memory used by the regexp JIT to hold generated code.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/unused-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.unusedCode,
|
||||
"Memory allocated by one of the JITs to hold the "
|
||||
"runtime's code, but which is currently unused.");
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/other"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.other,
|
||||
"Memory used by the JITs to hold generated code for "
|
||||
"wrappers and trampolines.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/code/unused"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.code.unused,
|
||||
"Memory allocated by one of the JITs to hold code, "
|
||||
"but which is currently unused.");
|
||||
|
||||
RREPORT_BYTES(rtPath + NS_LITERAL_CSTRING("runtime/regexp-data"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, rtStats.runtime.regexpData,
|
||||
|
@ -2136,7 +2136,8 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
||||
// Note that items without their own layers can't be skipped this
|
||||
// way, since their ThebesLayer may decide it wants to draw them
|
||||
// into its buffer even if they're currently covered.
|
||||
if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) {
|
||||
if (itemVisibleRect.IsEmpty() &&
|
||||
!item->ShouldBuildLayerEvenIfInvisible(mBuilder)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2192,7 +2193,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
||||
data->mDrawAboveRegion.SimplifyOutward(4);
|
||||
}
|
||||
itemVisibleRect.MoveBy(mParameters.mOffset);
|
||||
if (!nsDisplayTransform::IsLayerPrerendered(ownLayer)) {
|
||||
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
|
||||
}
|
||||
|
||||
// rounded rectangle clipping using mask layers
|
||||
// (must be done after visible rect is set on layer)
|
||||
|
@ -570,12 +570,24 @@ void nsDisplayListBuilder::MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame,
|
||||
nsRect dirty = aDirtyRect - aFrame->GetOffsetTo(aDirtyFrame);
|
||||
nsRect overflowRect = aFrame->GetVisualOverflowRect();
|
||||
|
||||
if (aFrame->IsTransformed() &&
|
||||
nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
|
||||
eCSSProperty_transform)) {
|
||||
/**
|
||||
* Add a fuzz factor to the overflow rectangle so that elements only just
|
||||
* out of view are pulled into the display list, so they can be
|
||||
* prerendered if necessary.
|
||||
*/
|
||||
overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
|
||||
}
|
||||
|
||||
if (mHasDisplayPort && IsFixedFrame(aFrame)) {
|
||||
dirty = overflowRect;
|
||||
}
|
||||
|
||||
if (!dirty.IntersectRect(dirty, overflowRect))
|
||||
return;
|
||||
|
||||
aFrame->Properties().Set(nsDisplayListBuilder::OutOfFlowDirtyRectProperty(),
|
||||
new nsRect(dirty));
|
||||
|
||||
@ -3891,7 +3903,14 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
|
||||
nsIFrame* aFrame,
|
||||
bool aLogAnimations)
|
||||
{
|
||||
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
|
||||
// Elements whose transform has been modified recently, or which
|
||||
// have a compositor-animated transform, can be prerendered. An element
|
||||
// might have only just had its transform animated in which case
|
||||
// nsChangeHint_UpdateTransformLayer will not be present yet.
|
||||
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
|
||||
(!aFrame->GetContent() ||
|
||||
!nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
|
||||
eCSSProperty_transform))) {
|
||||
if (aLogAnimations) {
|
||||
nsCString message;
|
||||
message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
|
||||
@ -3978,6 +3997,12 @@ nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
|
||||
return mTransform;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayTransform::ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
return ShouldPrerenderTransformedContent(aBuilder, mFrame, false);
|
||||
}
|
||||
|
||||
already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder,
|
||||
LayerManager *aManager,
|
||||
const ContainerParameters& aContainerParameters)
|
||||
|
@ -966,6 +966,12 @@ public:
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aParameters)
|
||||
{ return mozilla::LAYER_NONE; }
|
||||
/**
|
||||
* Return true to indicate the layer should be constructed even if it's
|
||||
* completely invisible.
|
||||
*/
|
||||
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder)
|
||||
{ return false; }
|
||||
/**
|
||||
* Actually paint this item to some rendering context.
|
||||
* Content outside mVisibleRect need not be painted.
|
||||
@ -2533,7 +2539,8 @@ public:
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aParameters) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
|
||||
{ return true; }
|
||||
virtual bool TryMerge(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayItem* aItem) MOZ_OVERRIDE;
|
||||
|
||||
@ -2789,6 +2796,7 @@ public:
|
||||
virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aContainerParameters) MOZ_OVERRIDE;
|
||||
virtual bool ShouldBuildLayerEvenIfInvisible(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
virtual bool ComputeVisibility(nsDisplayListBuilder *aBuilder,
|
||||
nsRegion *aVisibleRegion,
|
||||
const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE;
|
||||
@ -2940,6 +2948,11 @@ public:
|
||||
bool aLogAnimations = false);
|
||||
bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE;
|
||||
|
||||
static bool IsLayerPrerendered(Layer* aLayer)
|
||||
{
|
||||
return aLayer->HasUserData(nsIFrame::LayerIsPrerenderedDataKey());
|
||||
}
|
||||
|
||||
private:
|
||||
static gfx3DMatrix GetResultingTransformMatrixInternal(const FrameTransformProperties& aProperties,
|
||||
const nsPoint& aOrigin,
|
||||
|
@ -130,10 +130,6 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
|
||||
}
|
||||
|
||||
for (nsDisplayItem* i = aList.GetBottom(); i != nullptr; i = i->GetAbove()) {
|
||||
#ifdef DEBUG
|
||||
if (aList.DidComputeVisibility() && i->GetVisibleRect().IsEmpty())
|
||||
continue;
|
||||
#endif
|
||||
if (aDumpHtml) {
|
||||
fprintf(aOutput, "<li>");
|
||||
} else {
|
||||
|
@ -2054,6 +2054,18 @@ IsRootScrollFrameActive(nsIPresShell* aPresShell)
|
||||
return sf && sf->IsScrollingActive();
|
||||
}
|
||||
|
||||
static nsDisplayItem*
|
||||
WrapInWrapList(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList)
|
||||
{
|
||||
nsDisplayItem* item = aList->GetBottom();
|
||||
if (!item || item->GetAbove() || item->GetUnderlyingFrame() != aFrame) {
|
||||
return new (aBuilder) nsDisplayWrapList(aBuilder, aFrame, aList);
|
||||
}
|
||||
aList->RemoveBottom();
|
||||
return item;
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aChild,
|
||||
@ -2288,7 +2300,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
if (buildFixedPositionItem) {
|
||||
item = new (aBuilder) nsDisplayFixedPosition(aBuilder, child, child, &list);
|
||||
} else {
|
||||
item = new (aBuilder) nsDisplayWrapList(aBuilder, child, &list);
|
||||
item = WrapInWrapList(aBuilder, child, &list);
|
||||
}
|
||||
if (isSVG) {
|
||||
aLists.Content()->AppendNewToTop(item);
|
||||
@ -2311,8 +2323,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
} else if (!isSVG && disp->IsFloating(child)) {
|
||||
if (!list.IsEmpty()) {
|
||||
aLists.Floats()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayWrapList(aBuilder, child, &list));
|
||||
aLists.Floats()->AppendNewToTop(WrapInWrapList(aBuilder, child, &list));
|
||||
}
|
||||
} else {
|
||||
aLists.Content()->AppendToTop(&list);
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
* @result The new view. Never null.
|
||||
*/
|
||||
nsView* CreateView(const nsRect& aBounds,
|
||||
const nsView* aParent,
|
||||
nsView* aParent,
|
||||
nsViewVisibility aVisibilityFlag = nsViewVisibility_kShow);
|
||||
|
||||
/**
|
||||
|
@ -126,11 +126,11 @@ nsViewManager::Init(nsDeviceContext* aContext)
|
||||
|
||||
nsView*
|
||||
nsViewManager::CreateView(const nsRect& aBounds,
|
||||
const nsView* aParent,
|
||||
nsView* aParent,
|
||||
nsViewVisibility aVisibilityFlag)
|
||||
{
|
||||
nsView *v = new nsView(this, aVisibilityFlag);
|
||||
v->SetParent(const_cast<nsView*>(aParent));
|
||||
v->SetParent(aParent);
|
||||
v->SetPosition(aBounds.x, aBounds.y);
|
||||
nsRect dim(0, 0, aBounds.width, aBounds.height);
|
||||
v->SetDimensions(dim, false);
|
||||
|
Loading…
Reference in New Issue
Block a user