mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:34:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:- Bug 1258966 - Remove unnecessary null-checks of MediaDecoderStateMachine::mReader. r=bechen. (0513c82214)
- Bug 1258627 - always schedule next cycle so MDSM has a chance to leave buffering state. r=cpearce. (49fb876b9e) - Bug 1258271 - Remove arguments from MediaDecoderStateMachine::HaveEnoughDecodedAudio(). r=bechen. (e8610f7f76) - Bug 1252753. Part 1 - remove calls to PushFront(). r=kinetik. (7abe1bfb0f) - Bug 1252753. Part 2 - remove MediaDecoderStateMachine::PushFront(). r=kinetik. (1a153a5b00) - Bug 1230527: P1. Ensure seeked event is fired prior loadeddata. r=jwwang (aa9eef9fd3) - Bug 1230527: P2. Add mochitest. r=jwwang (6e9f920781) - Bug 1252767 - Remove MediaDecoderStateMachine::mPendingSeek. r=cpearce. (e5d69a191d) - Bug 1255268 - Replace SeekJob::Steal() with move semantics. r=cpearce. (6294c01ba7) - Bug 1253490 - fix the calculation of decodeTime. r=jya. (b8f3c8801a) - Bug 1252343. Part 1 - make mReader const. r=bechen. (33a8b6a4ad) - Bug 1252343. Part 2 - remove null checks for mReader which is const and never null. r=bechen. (5cd068aafc) - Bug 1250054. Part 2 - employ MediaDecoderReaderWrapper for MDSM and remove code about adjusting start time. r=jya. (b5a954d8d8) - Bug 1252341 - No need to reset mReader in ~MediaDecoderStateMachine() because the destructor will do that. r=bechen. (cd0639e366) - Bug 1264784 - part 2 - remove unused virtual methods from nsIFrame; r=dholbert (5d52314a79) - Bug 1264784 - part 3 - make nsIFrame::GetNearestWidget methods non-virtual; r=dholbert (67b0987de6) - Bug 1053986 - Rename nsIFrame::IsBoxFrame to IsXULBoxFrame. r=dholbert (394613f49f) - Bug 1256040 - Fix some nsGridContainerFrame.h/cpp compile errors in non-unified build. r=dholbert (b49241e3b1) - Bug 1264607 - Treat track size <percentage> values as 'auto' when the grid container size is indefinite. r=dholbert (3895d4d922) - Bug 1260614 - Cleanup grid item iterator Reset() calls. r=dholbert (e6760e1def) - Bug 1256040 - Bustage fix. r=me (d67b9c0de5) - Bug 1233191 part 1 - Implement sanity checks on the flex/grid container child frame list. Remove the anon grid item sanity checks that the frame constructor now does instead. r=dholbert (d9412bb043) - Bug 1233191 part 2 - Remove anon flex item sanity checks that the frame constructor now does instead. r=dholbert (564184ea6d) - Bug 1233191 part 3 - crashtest. (c6b6bb4fca) - Bug 1187846 Stack layout doesn't honour min/max sizes for positioned elements r=Enn (8080e9db71) - Bug 1053986 - Rename nsIFrame::GetMinSize to GetXULMinSize, and related methods. r=dholbert (fa1722982e) - Bug 1000870 - Add some features in testing system. r=smaug (f7b4b8916f) - Bug 1053986 - Rename nsIFrame::GetPrefSize to GetXULPrefSize, and related methods. r=dholbert (9f7e8de26e) - Bug 1053986 - Rename nsIFrame::GetMaxSize to GetXULMaxSize, and related methods. r=dholbert (a632913886) - Bug 1053986 - Rename nsIFrame::GetMinSizeForScrollArea to GetXULMinSizeForScrollArea. r=dholbert (ac520afe6f) - Bug 1053986 - Rename nsIFrame::GetOrdinal to GetXULOrdinal. r=dholbert (e5f7342d03) - Bug 1053986 - Rename nsIFrame::GetFlex to GetXULFlex. r=dholbert (aadf567a8c) - Bug 1053986 - Rename nsIFrame::GetBoxAscent to GetXULBoxAscent. r=dholbert (4e729c60ea) - Bug 1053986 - Rename nsFrame.cpp static method IsBoxWrapped to IsXULBoxWrapped. r=dholbert (009b251df0) - Bug 1053986 - Rename nsIFrame::IsCollapsed to IsXULCollapsed, and related methods. r=dholbert (eec509e378) - Bug 1168212 - Ensure popups have a minimum width of their preferred size r=Enn (657c8da6fa) - Bug 1053986 - Rename nsIFrame::SetBounds to SetXULBounds. r=dholbert (304ff47c6c) - Bug 1088637 - check we get the right transition event, r=Enn (b0da4a67f6) - Bug 1053986 - Rename nsIFrame::Layout to XULLayout, and related methods with the same name. r=dholbert (66ef396b10) - Bug 1053986 - Rename nsIFrame::GetBorderAndPadding to GetXULBorderAndPadding. r=dholbert (588f824000) - Bug 1053986 - Rename nsIFrame::GetBorder to GetXULBorder. r=dholbert (f91ae3fc59) - Bug 1053986 - Rename nsIFrame::GetPadding to GetXULPadding. r=dholbert (797e21e6af) - Bug 1053986 - Rename nsIFrame::GetMargin to GetXULMargin. r=dholbert (05dc0235f2) - Bug 1053986 - Rename nsIFrame::SetLayoutManager to SetXULLayoutManager. r=dholbert (0cb22c411d) - Bug 1053986 - Rename nsIFrame::GetLayoutManager to GetXULLayoutManager. r=dholbert (6a03e1de2c) - Bug 852754 - Part 1: Share the code for limiting scale factors to all image types. r=mstange (098a083d1a) - Bug 852754 - Part 2: Share the implementation of GetContainer. r=mstange (063b7683dd) - Bug 852754 - Part 3: Share the implementation of ConfigureLayer. r=mstange (ffd2d99802) - Bug 1256999 - Pass the right context to new channels for image loads. r=bz r=seth (275cebb231) - Bug 1194337 - Context menu positioned incorrectly on OSX. r=enn (1e429a9d3c) - Bug 1216284 - Tooltips do not flip correctly on OSX. r=enndeakin (c08931768b) - Bug 1053986 - Rename nsIFrame::GetClientRect to GetXULClientRect. r=dholbert (c06a121de6) - Bug 1053986 - Rename nsIFrame::GetVAlign to GetXULVAlign. r=dholbert (a923d76c4b) - Bug 1053986 - Rename nsBox::GetChildBox to GetChildXULBox. r=dholbert (ebe12c77f1) - Bug 1053986 - Rename nsIFrame::GetHAlign to GetXULHAlign. r=dholbert (dbd501e2bd) - Bug 1053986 - Rename nsBox::GetNextBox to GetNextXULBox. r=dholbert (1cd5fa1ce3) - Bug 1053986 - Rename nsBox::GetParentBox to GetParentXULBox. r=dholbert (2beaeb6bdd) - Bug 1171696 - Don't resize scrollbar thumb when updating its position. r=mstange (5b51241744) - Bug 1053986 - Rename nsIFrame::IsHorizontal to IsXULHorizontal, and related methods. r=dholbert (7d8e4142e5) - Bug 1053986 - Rename nsIFrame::IsNormalDirection to IsXULNormalDirection. r=dholbert (7d9686b089) - Bug 1053986 - Rename nsIFrame::Redraw to XULRedraw. r=dholbert (20da19c2ce) - Bug 1053986 - Rename nsIFrame::RelayoutChildAtOrdinal to XULRelayoutChildAtOrdinal. r=dholbert (e5c4eb2b9f) - Bug 1053986 - Rename nsIFrame::SetDebug to SetXULDebug. r=dholbert (438c3a1109) - Bug 1053986 - Rename nsIFrame::GetDebug to GetXULDebug. r=dholbert (00e0ca19e4) - Bug 1053986 - Rename nsIFrame::DumpBox to XULDumpBox. r=dholbert (30edc21d8e) - Bug 1053986 - Rename nsIFrame::AddCSSPrefSize, AddCSSMinSize, AddCSSMaxSize, and AddCSSFlex by replacing CSS with XUL. r=dholbert (4e79b90b1f) - Bug 1053986 - Fix ordering of methods in nsIFrame.h r=dholbert (fb08aa035f) - Bug 1053986 - Rename nsBox::BeginLayout to BeginXULLayout. r=dholbert (595cb70526) - Bug 1053986 - Rename nsBox::EndLayout to EndXULLayout. r=dholbert (13f98a84a0) - Bug 1213895: Part 1 - Correctly support crop="none" in XUL labels. r=neil (053e0c8414) - Bug 1053986 - Rename nsBox::DoLayout to DoXULLayout. r=dholbert (40ef0ece53) - Bug 1144619 - Variable 'nextX' is created in the wrong scope. r=dbaron (7893ccb301) - Bug 1172011 - Remove unneeded 'spaceLeft' declaration from nsSplitterFrame.cpp. r=froydnj (7ef937e283) - Bug 1192376: Make nsImageBoxFrame check whether image size is available before trying to paint an image. r=seth (2db203eb3b) - Bug 1240533 - Parameters to ScreenForRect need to be passed as desktop pixels, not device pixels. r=emk (d49b532344) - Bug 1212658 - Remove needless IsCallerChrome check in nsMenuPopupFrame. r=bz (bdf0d16a49) - Bug 374471 Make the noautohide attribute live where supported r=enndeakin (f696b4d174) - Bug 1200870, allow -1 as a value to popup.moveTo, r=tn (10e05d4240) - Bug 1182856 - Part 1: Add StopTransitionsForElement. r=heycam (1c0ac374c4) - Bug 1182856 - Part 2: Let AnimationsWithDestroyFrame destroy transitions. r=heycam (7820f7b1e5) - Bug 1182856 - Part 3: Cancel transitions for destroy frames. r=heycam (439fb07545) - Bug 1157936 - Put the correct ratio on the scrollbar layer. r=tn (a64f35b9ea) - Bug 1238137 - Telemetry pings for main thread scrollbar-driven scroll input methods. r=kats (89e5187b88) - Bug 1156106 - Make nsMenuBarFrame::mMenuBarListener an nsRefPtr; r=roc (838126cd16) - Bug 1163304 Close all existing popups when menubar becomes active because it should have pseudo focus and other popups shouldn't handle key events r=enn+neil (933c9ae40e) - Bug 1252693 - Assert that we do not tenure into an OMT Zone; r=sfink (0812fc81f2) - Bug 1265679 - Always call the object moved hook in generational GC r=terrence (6d75efba2d) - Bug 1265825 - Remove mSuppressionActive assert. r=kats (3b6b3ba030) - Bug 1250226 - Only report compacting GC telemetry for compacting GCs r=terrence (4e0f511ccf) - Bug 1258578: Improve documentation for js::RelocatablePtr. DONTBUILD r=terrence (3ed2a933e0) - Bug 1252713 - Fix FILES_PER_UNIFIED_FILE=1 bustage in js/. r=terrence (8a97e6c7e2) - Bug 1265741: Fix unified build for fuzzers; r=nbp (ad3b4a4543) - Bug 1013219 - set the line number of the terminating retrval; r=jimb, r=ejpbruel, r=fitzgen (df810884a9) - Bug 1013219 - set line number of return instruction; r=efaust, r=fitzgen, r=ejpbruel (503b1a2bf3) - Bug 1260577 - Fix |obj[expr] += e2| erroneously calling expr.toString() twice. (r=till) (e2485baccb) - Bug 1260577 - followup: Change confusing name SelfAssign to CompoundAssign. (rs=jorendorff) (51a7dee68e) - Bug 1263881 - Check the the number of body level lexicals doesn't exceed that which we can store in Bindings r=shu (d610d7a1e9) - Bug 1258097 - Check for redeclaration of imports by functions r=shu (78f06f273f) - Bug 1264954 - Add missing OOM check in Parser::templateLiteral. r=jonco (2743a82e1e) - Bug 1265313 - Fix Annex B.3.5 handling with body-level lexicals. (r=jorendorff) (6b4139d25b) - Bug 1260620 - Ensure that possibleErrors are not null before attempting to check them; r=jorendorff (6b284c1107) - Bug 1253275 - Remove const_casts from Runtime.cpp. r=sfink (40b6d68455) - Bug 1262731 - Add JS_InitWithFailureDiagnostic(). r=sfink. (310579fcd3) - Bug 1263886 - Don't call makeConstructorCode if the group has unknown properties. r=bhackett (e81c939928) - Bug 1260891 - Acquire and release the lock when destorying an `ExclusiveData<T>`'s protected value; r=terrence a=kwierso (dc39af575e) - Bug 1252034 - Value Numbering: Unconditionally generate fixup blocks. r=sunfish (3b46b2df51) - Bug 1232229 - Ensure generator object prototype is a singleton and tenured. r=jonco (d0c4f17cb6)
This commit is contained in:
@@ -432,9 +432,9 @@ Accessible::NativeState()
|
||||
|
||||
// XXX we should look at layout for non XUL box frames, but need to decide
|
||||
// how that interacts with ARIA.
|
||||
if (HasOwnContent() && mContent->IsXULElement() && frame->IsBoxFrame()) {
|
||||
if (HasOwnContent() && mContent->IsXULElement() && frame->IsXULBoxFrame()) {
|
||||
const nsStyleXUL* xulStyle = frame->StyleXUL();
|
||||
if (xulStyle && frame->IsBoxFrame()) {
|
||||
if (xulStyle && frame->IsXULBoxFrame()) {
|
||||
// In XUL all boxes are either vertical or horizontal
|
||||
if (xulStyle->mBoxOrient == NS_STYLE_BOX_ORIENT_VERTICAL)
|
||||
state |= states::VERTICAL;
|
||||
|
||||
@@ -1066,7 +1066,7 @@ HTMLTableAccessible::IsProbablyLayoutTable()
|
||||
RETURN_LAYOUT_ANSWER(false, "table's first cell has no frame!");
|
||||
|
||||
nsMargin border;
|
||||
cellFrame->GetBorder(border);
|
||||
cellFrame->GetXULBorder(border);
|
||||
if (border.top && border.bottom && border.left && border.right) {
|
||||
RETURN_LAYOUT_ANSWER(false, "Has nonzero border-width on table cell");
|
||||
}
|
||||
|
||||
@@ -3142,7 +3142,8 @@ nsContentUtils::IsImageInCache(nsIURI* aURI, nsIDocument* aDocument)
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
nsContentUtils::LoadImage(nsIURI* aURI, nsINode* aContext,
|
||||
nsIDocument* aLoadingDocument,
|
||||
nsIPrincipal* aLoadingPrincipal, nsIURI* aReferrer,
|
||||
net::ReferrerPolicy aReferrerPolicy,
|
||||
imgINotificationObserver* aObserver, int32_t aLoadFlags,
|
||||
@@ -3151,6 +3152,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
uint32_t aContentPolicyType)
|
||||
{
|
||||
NS_PRECONDITION(aURI, "Must have a URI");
|
||||
NS_PRECONDITION(aContext, "Must have a context");
|
||||
NS_PRECONDITION(aLoadingDocument, "Must have a document");
|
||||
NS_PRECONDITION(aLoadingPrincipal, "Must have a principal");
|
||||
NS_PRECONDITION(aRequest, "Null out param");
|
||||
@@ -3180,6 +3182,7 @@ nsContentUtils::LoadImage(nsIURI* aURI, nsIDocument* aLoadingDocument,
|
||||
aLoadingPrincipal, /* loading principal */
|
||||
loadGroup, /* loadgroup */
|
||||
aObserver, /* imgINotificationObserver */
|
||||
aContext, /* loading context */
|
||||
aLoadingDocument, /* uniquification key */
|
||||
aLoadFlags, /* load flags */
|
||||
nullptr, /* cache key */
|
||||
@@ -7636,6 +7639,8 @@ int16_t
|
||||
nsContentUtils::GetButtonsFlagForButton(int32_t aButton)
|
||||
{
|
||||
switch (aButton) {
|
||||
case -1:
|
||||
return WidgetMouseEvent::eNoButtonFlag;
|
||||
case WidgetMouseEvent::eLeftButton:
|
||||
return WidgetMouseEvent::eLeftButtonFlag;
|
||||
case WidgetMouseEvent::eMiddleButton:
|
||||
|
||||
@@ -662,6 +662,8 @@ public:
|
||||
* keep a mutable version around should pass in a clone.
|
||||
*
|
||||
* @param aURI uri of the image to be loaded
|
||||
* @param aContext element of document where the result of this request
|
||||
* will be used.
|
||||
* @param aLoadingDocument the document we belong to
|
||||
* @param aLoadingPrincipal the principal doing the load
|
||||
* @param aReferrer the referrer URI
|
||||
@@ -674,6 +676,7 @@ public:
|
||||
* @return the imgIRequest for the image load
|
||||
*/
|
||||
static nsresult LoadImage(nsIURI* aURI,
|
||||
nsINode* aContext,
|
||||
nsIDocument* aLoadingDocument,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
nsIURI* aReferrer,
|
||||
|
||||
@@ -9794,6 +9794,7 @@ nsDocument::MaybePreLoadImage(nsIURI* uri, const nsAString &aCrossOriginAttr,
|
||||
RefPtr<imgRequestProxy> request;
|
||||
nsresult rv =
|
||||
nsContentUtils::LoadImage(uri,
|
||||
static_cast<nsINode*>(this),
|
||||
this,
|
||||
NodePrincipal(),
|
||||
mDocumentURI, // uri of document used as referrer
|
||||
|
||||
@@ -878,7 +878,11 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI,
|
||||
// Not blocked. Do the load.
|
||||
RefPtr<imgRequestProxy>& req = PrepareNextRequest(aImageLoadType);
|
||||
nsIContent* content = AsContent();
|
||||
nsresult rv = nsContentUtils::LoadImage(aNewURI, aDocument,
|
||||
nsCOMPtr<nsINode> thisNode =
|
||||
do_QueryInterface(static_cast<nsIImageLoadingContent*>(this));
|
||||
nsresult rv = nsContentUtils::LoadImage(aNewURI,
|
||||
thisNode,
|
||||
aDocument,
|
||||
aDocument->NodePrincipal(),
|
||||
aDocument->GetDocumentURI(),
|
||||
referrerPolicy,
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "ImageContainer.h"
|
||||
#include "MediaDecoder.h"
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "MediaDecoderReaderWrapper.h"
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "MediaShutdownManager.h"
|
||||
#include "MediaTimer.h"
|
||||
@@ -219,6 +220,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
|
||||
mObservedDuration(TimeUnit(), "MediaDecoderStateMachine::mObservedDuration"),
|
||||
mFragmentEndTime(-1),
|
||||
mReader(aReader),
|
||||
mReaderWrapper(new MediaDecoderReaderWrapper(aRealTime, mTaskQueue, aReader)),
|
||||
mDecodedAudioEndTime(0),
|
||||
mDecodedVideoEndTime(0),
|
||||
mPlaybackRate(1.0),
|
||||
@@ -332,8 +334,6 @@ MediaDecoderStateMachine::~MediaDecoderStateMachine()
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread.");
|
||||
MOZ_COUNT_DTOR(MediaDecoderStateMachine);
|
||||
|
||||
mReader = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
timeEndPeriod(1);
|
||||
#endif
|
||||
@@ -464,12 +464,13 @@ void MediaDecoderStateMachine::DiscardStreamData()
|
||||
}
|
||||
}
|
||||
|
||||
bool MediaDecoderStateMachine::HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs)
|
||||
bool MediaDecoderStateMachine::HaveEnoughDecodedAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
int64_t ampleAudioUSecs = mAmpleAudioThresholdUsecs * mPlaybackRate;
|
||||
if (AudioQueue().GetSize() == 0 ||
|
||||
GetDecodedAudioDuration() < aAmpleAudioUSecs) {
|
||||
GetDecodedAudioDuration() < ampleAudioUSecs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -566,14 +567,12 @@ MediaDecoderStateMachine::NeedToDecodeAudio()
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
SAMPLE_LOG("NeedToDecodeAudio() isDec=%d minPrl=%d enufAud=%d",
|
||||
IsAudioDecoding(), mMinimizePreroll,
|
||||
HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate));
|
||||
IsAudioDecoding(), mMinimizePreroll, HaveEnoughDecodedAudio());
|
||||
|
||||
return IsAudioDecoding() &&
|
||||
mState != DECODER_STATE_SEEKING &&
|
||||
((IsDecodingFirstFrame() && AudioQueue().GetSize() == 0) ||
|
||||
(!mMinimizePreroll &&
|
||||
!HaveEnoughDecodedAudio(mAmpleAudioThresholdUsecs * mPlaybackRate)));
|
||||
(!mMinimizePreroll && !HaveEnoughDecodedAudio()));
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -609,7 +608,6 @@ MediaDecoderStateMachine::OnAudioDecoded(MediaData* aAudioSample)
|
||||
RefPtr<MediaData> audio(aAudioSample);
|
||||
MOZ_ASSERT(audio);
|
||||
mAudioDataRequest.Complete();
|
||||
aAudioSample->AdjustForStartTime(StartTime());
|
||||
|
||||
// audio->GetEndTime() is not always mono-increasing in chained ogg.
|
||||
mDecodedAudioEndTime = std::max(audio->GetEndTime(), mDecodedAudioEndTime);
|
||||
@@ -707,22 +705,6 @@ MediaDecoderStateMachine::Push(MediaData* aSample, MediaData::Type aSampleType)
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::PushFront(MediaData* aSample, MediaData::Type aSampleType)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
MOZ_ASSERT(aSample);
|
||||
if (aSample->mType == MediaData::AUDIO_DATA) {
|
||||
AudioQueue().PushFront(aSample);
|
||||
} else if (aSample->mType == MediaData::VIDEO_DATA) {
|
||||
aSample->As<VideoData>()->mFrameID = ++mCurrentFrameID;
|
||||
VideoQueue().PushFront(aSample);
|
||||
} else {
|
||||
// TODO: Handle MediaRawData, determine which queue should be pushed.
|
||||
}
|
||||
UpdateNextFrameStatus();
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::CheckIsAudible(const MediaData* aSample)
|
||||
{
|
||||
@@ -852,6 +834,11 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
|
||||
return;
|
||||
}
|
||||
CheckIfDecodeComplete();
|
||||
|
||||
// Schedule next cycle to see if we can leave buffering state.
|
||||
if (mState == DECODER_STATE_BUFFERING) {
|
||||
ScheduleStateMachine();
|
||||
}
|
||||
return;
|
||||
}
|
||||
case DECODER_STATE_SEEKING: {
|
||||
@@ -890,20 +877,19 @@ MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
|
||||
}
|
||||
|
||||
// We can now complete the pending seek.
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
InitiateSeek(Move(mQueuedSeek));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample,
|
||||
TimeStamp aDecodeStartTime)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
RefPtr<MediaData> video(aVideoSample);
|
||||
MOZ_ASSERT(video);
|
||||
mVideoDataRequest.Complete();
|
||||
aVideoSample->AdjustForStartTime(StartTime());
|
||||
|
||||
// Handle abnormal or negative timestamps.
|
||||
mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, video->GetEndTime());
|
||||
@@ -939,7 +925,7 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
if (mReader->IsAsync()) {
|
||||
return;
|
||||
}
|
||||
TimeDuration decodeTime = TimeStamp::Now() - mVideoDecodeStartTime;
|
||||
TimeDuration decodeTime = TimeStamp::Now() - aDecodeStartTime;
|
||||
if (!IsDecodingFirstFrame() &&
|
||||
THRESHOLD_FACTOR * DurationToUsecs(decodeTime) > mLowAudioThresholdUsecs &&
|
||||
!HasLowUndecodedData())
|
||||
@@ -977,10 +963,8 @@ MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideoSample)
|
||||
// in this case, we'll just decode forward. Bug 1026330.
|
||||
mCurrentSeek.mTarget.SetType(SeekTarget::Accurate);
|
||||
}
|
||||
if (mCurrentSeek.mTarget.IsFast() ||
|
||||
mPendingSeek.Exists()) {
|
||||
// Non-precise seek; or a pending seek exists ; we can stop the seek
|
||||
// at the first sample.
|
||||
if (mCurrentSeek.mTarget.IsFast()) {
|
||||
// Non-precise seek. We can stop the seek at the first sample.
|
||||
Push(video, MediaData::VIDEO_DATA);
|
||||
} else {
|
||||
// We're doing an accurate seek. We still need to discard
|
||||
@@ -1274,10 +1258,6 @@ MediaDecoderStateMachine::SetDormant(bool aDormant)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mReader) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mMetadataRequest.Exists()) {
|
||||
if (mPendingDormant && mPendingDormant.ref() != aDormant && !aDormant) {
|
||||
// We already have a dormant request pending; the new request would have
|
||||
@@ -1296,10 +1276,8 @@ MediaDecoderStateMachine::SetDormant(bool aDormant)
|
||||
if (mState == DECODER_STATE_SEEKING) {
|
||||
if (mQueuedSeek.Exists()) {
|
||||
// Keep latest seek target
|
||||
} else if (mPendingSeek.Exists()) {
|
||||
mQueuedSeek.Steal(mPendingSeek);
|
||||
} else if (mCurrentSeek.Exists()) {
|
||||
mQueuedSeek.Steal(mCurrentSeek);
|
||||
mQueuedSeek = Move(mCurrentSeek);
|
||||
} else {
|
||||
mQueuedSeek.mTarget = SeekTarget(mCurrentPosition,
|
||||
SeekTarget::Accurate,
|
||||
@@ -1316,7 +1294,6 @@ MediaDecoderStateMachine::SetDormant(bool aDormant)
|
||||
// back to MediaDecoder when we come out of dormant?
|
||||
RefPtr<MediaDecoder::SeekPromise> unused = mQueuedSeek.mPromise.Ensure(__func__);
|
||||
}
|
||||
mPendingSeek.RejectIfExists(__func__);
|
||||
mCurrentSeek.RejectIfExists(__func__);
|
||||
SetState(DECODER_STATE_DORMANT);
|
||||
if (IsPlaying()) {
|
||||
@@ -1354,7 +1331,6 @@ MediaDecoderStateMachine::Shutdown()
|
||||
mBufferedUpdateRequest.DisconnectIfExists();
|
||||
|
||||
mQueuedSeek.RejectIfExists(__func__);
|
||||
mPendingSeek.RejectIfExists(__func__);
|
||||
mCurrentSeek.RejectIfExists(__func__);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
@@ -1368,11 +1344,7 @@ MediaDecoderStateMachine::Shutdown()
|
||||
Reset();
|
||||
|
||||
mMediaSink->Shutdown();
|
||||
|
||||
// Shut down our start time rendezvous.
|
||||
if (mStartTimeRendezvous) {
|
||||
mStartTimeRendezvous->Destroy();
|
||||
}
|
||||
mReaderWrapper->Shutdown();
|
||||
|
||||
DECODER_LOG("Shutdown started");
|
||||
|
||||
@@ -1408,9 +1380,8 @@ void MediaDecoderStateMachine::StartDecoding()
|
||||
"Return from dormant must have queued seek");
|
||||
}
|
||||
if (mQueuedSeek.Exists()) {
|
||||
mPendingSeek.Steal(mQueuedSeek);
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
InitiateSeek(Move(mQueuedSeek));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1510,8 +1481,7 @@ MediaDecoderStateMachine::ReadMetadata()
|
||||
DECODER_LOG("Dispatching AsyncReadMetadata");
|
||||
// Set mode to METADATA since we are about to read metadata.
|
||||
mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
|
||||
mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::AsyncReadMetadata)
|
||||
mMetadataRequest.Begin(mReaderWrapper->ReadMetadata()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnMetadataRead,
|
||||
&MediaDecoderStateMachine::OnMetadataNotRead));
|
||||
@@ -1544,14 +1514,14 @@ MediaDecoderStateMachine::Seek(SeekTarget aTarget)
|
||||
return mQueuedSeek.mPromise.Ensure(__func__);
|
||||
}
|
||||
mQueuedSeek.RejectIfExists(__func__);
|
||||
mPendingSeek.RejectIfExists(__func__);
|
||||
mPendingSeek.mTarget = aTarget;
|
||||
|
||||
DECODER_LOG("Changed state to SEEKING (to %lld)", mPendingSeek.mTarget.GetTime().ToMicroseconds());
|
||||
DECODER_LOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
ScheduleStateMachine();
|
||||
|
||||
return mPendingSeek.mPromise.Ensure(__func__);
|
||||
SeekJob seekJob;
|
||||
seekJob.mTarget = aTarget;
|
||||
InitiateSeek(Move(seekJob));
|
||||
return mCurrentSeek.mPromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
RefPtr<MediaDecoder::SeekPromise>
|
||||
@@ -1631,12 +1601,12 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
|
||||
}
|
||||
|
||||
void
|
||||
MediaDecoderStateMachine::InitiateSeek()
|
||||
MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
|
||||
{
|
||||
MOZ_ASSERT(OnTaskQueue());
|
||||
|
||||
mCurrentSeek.RejectIfExists(__func__);
|
||||
mCurrentSeek.Steal(mPendingSeek);
|
||||
mCurrentSeek = Move(aSeekJob);
|
||||
|
||||
// Bound the seek time to be inside the media range.
|
||||
int64_t end = Duration().ToMicroseconds();
|
||||
@@ -1665,11 +1635,8 @@ MediaDecoderStateMachine::InitiateSeek()
|
||||
|
||||
// Do the seek.
|
||||
RefPtr<MediaDecoderStateMachine> self = this;
|
||||
SeekTarget seekTarget = mCurrentSeek.mTarget;
|
||||
seekTarget.SetTime(seekTarget.GetTime() + media::TimeUnit::FromMicroseconds(StartTime()));
|
||||
mSeekRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::Seek, seekTarget,
|
||||
Duration().ToMicroseconds())
|
||||
mSeekRequest.Begin(
|
||||
mReaderWrapper->Seek(mCurrentSeek.mTarget, Duration())
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self] (media::TimeUnit) -> void {
|
||||
self->mSeekRequest.Complete();
|
||||
@@ -1731,25 +1698,11 @@ MediaDecoderStateMachine::RequestAudioData()
|
||||
SAMPLE_LOG("Queueing audio task - queued=%i, decoder-queued=%o",
|
||||
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
|
||||
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mAudioDataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(),
|
||||
__func__, &MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||
} else {
|
||||
mAudioDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestAudioData)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise, MediaData::AUDIO_DATA>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<MediaData::AUDIO_DATA>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded)
|
||||
);
|
||||
}
|
||||
mAudioDataRequest.Begin(
|
||||
mReaderWrapper->RequestAudioData()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnAudioDecoded,
|
||||
&MediaDecoderStateMachine::OnAudioNotDecoded));
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -1799,40 +1752,28 @@ MediaDecoderStateMachine::RequestVideoData()
|
||||
// Time the video decode, so that if it's slow, we can increase our low
|
||||
// audio threshold to reduce the chance of an audio underrun while we're
|
||||
// waiting for a video decode to complete.
|
||||
mVideoDecodeStartTime = TimeStamp::Now();
|
||||
TimeStamp videoDecodeStartTime = TimeStamp::Now();
|
||||
|
||||
bool skipToNextKeyFrame = mSentFirstFrameLoadedEvent &&
|
||||
NeedToSkipToNextKeyframe();
|
||||
|
||||
int64_t currentTime =
|
||||
mState == DECODER_STATE_SEEKING || !mSentFirstFrameLoadedEvent
|
||||
? 0 : GetMediaTime() + StartTime();
|
||||
media::TimeUnit currentTime = media::TimeUnit::FromMicroseconds(
|
||||
mState == DECODER_STATE_SEEKING ? 0 : GetMediaTime());
|
||||
|
||||
SAMPLE_LOG("Queueing video task - queued=%i, decoder-queued=%o, skip=%i, time=%lld",
|
||||
VideoQueue().GetSize(), mReader->SizeOfVideoQueueInFrames(), skipToNextKeyFrame,
|
||||
currentTime);
|
||||
currentTime.ToMicroseconds());
|
||||
|
||||
if (mSentFirstFrameLoadedEvent) {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime)
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
} else {
|
||||
mVideoDataRequest.Begin(
|
||||
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
|
||||
&MediaDecoderReader::RequestVideoData,
|
||||
skipToNextKeyFrame, currentTime)
|
||||
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
|
||||
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise, MediaData::VIDEO_DATA>,
|
||||
&StartTimeRendezvous::FirstSampleRejected<MediaData::VIDEO_DATA>)
|
||||
->CompletionPromise()
|
||||
->Then(OwnerThread(), __func__, this,
|
||||
&MediaDecoderStateMachine::OnVideoDecoded,
|
||||
&MediaDecoderStateMachine::OnVideoNotDecoded));
|
||||
}
|
||||
RefPtr<MediaDecoderStateMachine> self = this;
|
||||
mVideoDataRequest.Begin(
|
||||
mReaderWrapper->RequestVideoData(skipToNextKeyFrame, currentTime)
|
||||
->Then(OwnerThread(), __func__,
|
||||
[self, videoDecodeStartTime] (MediaData* aVideoSample) {
|
||||
self->OnVideoDecoded(aVideoSample, videoDecodeStartTime);
|
||||
},
|
||||
[self] (MediaDecoderReader::NotDecodedReason aReason) {
|
||||
self->OnVideoNotDecoded(aReason);
|
||||
}));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1974,29 +1915,14 @@ MediaDecoderStateMachine::OnMetadataRead(MetadataHolder* aMetadata)
|
||||
mMetadataTags = aMetadata->mTags.forget();
|
||||
RefPtr<MediaDecoderStateMachine> self = this;
|
||||
|
||||
// Set up the start time rendezvous if it doesn't already exist (which is
|
||||
// generally the case, unless we're coming out of dormant mode).
|
||||
if (!mStartTimeRendezvous) {
|
||||
mStartTimeRendezvous = new StartTimeRendezvous(OwnerThread(), HasAudio(), HasVideo(),
|
||||
mReader->ForceZeroStartTime() || IsRealTime());
|
||||
|
||||
mStartTimeRendezvous->AwaitStartTime()->Then(OwnerThread(), __func__,
|
||||
[self] () -> void {
|
||||
NS_ENSURE_TRUE_VOID(!self->IsShutdown());
|
||||
self->mReader->DispatchSetStartTime(self->StartTime());
|
||||
},
|
||||
[] () -> void { NS_WARNING("Setting start time on reader failed"); }
|
||||
);
|
||||
}
|
||||
|
||||
if (mInfo.mMetadataDuration.isSome()) {
|
||||
RecomputeDuration();
|
||||
} else if (mInfo.mUnadjustedMetadataEndTime.isSome()) {
|
||||
mStartTimeRendezvous->AwaitStartTime()->Then(OwnerThread(), __func__,
|
||||
mReaderWrapper->AwaitStartTime()->Then(OwnerThread(), __func__,
|
||||
[self] () -> void {
|
||||
NS_ENSURE_TRUE_VOID(!self->IsShutdown());
|
||||
TimeUnit unadjusted = self->mInfo.mUnadjustedMetadataEndTime.ref();
|
||||
TimeUnit adjustment = TimeUnit::FromMicroseconds(self->StartTime());
|
||||
TimeUnit adjustment = self->mReaderWrapper->StartTime();
|
||||
self->mInfo.mMetadataDuration.emplace(unadjusted - adjustment);
|
||||
self->RecomputeDuration();
|
||||
}, [] () -> void { NS_WARNING("Adjusting metadata end time failed"); }
|
||||
@@ -2157,34 +2083,36 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
newCurrentTime = video ? video->mTime : seekTime;
|
||||
}
|
||||
|
||||
if (mDecodingFirstFrame) {
|
||||
// We were resuming from dormant, or initiated a seek early.
|
||||
// We can fire loadeddata now.
|
||||
FinishDecodeFirstFrame();
|
||||
}
|
||||
|
||||
// Change state to DECODING or COMPLETED now. SeekingStopped will
|
||||
// call MediaDecoderStateMachine::Seek to reset our state to SEEKING
|
||||
// if we need to seek again.
|
||||
|
||||
// Change state to DECODING or COMPLETED now.
|
||||
bool isLiveStream = mResource->IsLiveStream();
|
||||
if (mPendingSeek.Exists()) {
|
||||
// A new seek target came in while we were processing the old one. No rest
|
||||
// for the seeking.
|
||||
DECODER_LOG("A new seek came along while we were finishing the old one - staying in SEEKING");
|
||||
SetState(DECODER_STATE_SEEKING);
|
||||
} else if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
|
||||
State nextState;
|
||||
if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) {
|
||||
// Seeked to end of media, move to COMPLETED state. Note we don't do
|
||||
// this when playing a live stream, since the end of media will advance
|
||||
// once we download more data!
|
||||
DECODER_LOG("Changed state from SEEKING (to %lld) to COMPLETED", seekTime);
|
||||
// Explicitly set our state so we don't decode further, and so
|
||||
// we report playback ended to the media element.
|
||||
SetState(DECODER_STATE_COMPLETED);
|
||||
DispatchDecodeTasksIfNeeded();
|
||||
nextState = DECODER_STATE_COMPLETED;
|
||||
} else {
|
||||
DECODER_LOG("Changed state from SEEKING (to %lld) to DECODING", seekTime);
|
||||
nextState = DECODER_STATE_DECODING;
|
||||
}
|
||||
|
||||
// We want to resolve the seek request prior finishing the first frame
|
||||
// to ensure that the seeked event is fired prior loadeded.
|
||||
mCurrentSeek.Resolve(nextState == DECODER_STATE_COMPLETED, __func__);
|
||||
|
||||
if (mDecodingFirstFrame) {
|
||||
// We were resuming from dormant, or initiated a seek early.
|
||||
// We can fire loadeddata now.
|
||||
FinishDecodeFirstFrame();
|
||||
}
|
||||
|
||||
if (nextState == DECODER_STATE_DECODING) {
|
||||
StartDecoding();
|
||||
} else {
|
||||
SetState(nextState);
|
||||
}
|
||||
|
||||
// Ensure timestamps are up to date.
|
||||
@@ -2198,7 +2126,6 @@ MediaDecoderStateMachine::SeekCompleted()
|
||||
// if we need to buffer after the seek.
|
||||
mQuickBuffering = false;
|
||||
|
||||
mCurrentSeek.Resolve(mState == DECODER_STATE_COMPLETED, __func__);
|
||||
ScheduleStateMachine();
|
||||
|
||||
if (video) {
|
||||
@@ -2347,9 +2274,6 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
|
||||
}
|
||||
|
||||
case DECODER_STATE_SEEKING: {
|
||||
if (mPendingSeek.Exists()) {
|
||||
InitiateSeek();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -2531,7 +2455,8 @@ MediaDecoderStateMachine::DropVideoUpToSeekTarget(MediaData* aSample)
|
||||
DECODER_LOG("DropVideoUpToSeekTarget() found video frame [%lld, %lld] containing target=%lld",
|
||||
video->mTime, video->GetEndTime(), target);
|
||||
|
||||
PushFront(video, MediaData::VIDEO_DATA);
|
||||
MOZ_ASSERT(VideoQueue().GetSize() == 0, "Should be the 1st sample after seeking");
|
||||
Push(video, MediaData::VIDEO_DATA);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -2607,7 +2532,8 @@ MediaDecoderStateMachine::DropAudioUpToSeekTarget(MediaData* aSample)
|
||||
Move(audioData),
|
||||
channels,
|
||||
audio->mRate));
|
||||
PushFront(data, MediaData::AUDIO_DATA);
|
||||
MOZ_ASSERT(AudioQueue().GetSize() == 0, "Should be the 1st sample after seeking");
|
||||
Push(data, MediaData::AUDIO_DATA);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,7 @@ class MediaSink;
|
||||
|
||||
class AudioSegment;
|
||||
class DecodedStream;
|
||||
class MediaDecoderReaderWrapper;
|
||||
class OutputStreamManager;
|
||||
class TaskQueue;
|
||||
|
||||
@@ -210,12 +211,10 @@ public:
|
||||
OwnerThread()->Dispatch(r.forget());
|
||||
}
|
||||
|
||||
// Drop reference to mReader and mResource. Only called during shutdown dance.
|
||||
// Drop reference to mResource. Only called during shutdown dance.
|
||||
void BreakCycles() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mReader) {
|
||||
mReader->BreakCycles();
|
||||
}
|
||||
mReader->BreakCycles();
|
||||
mResource = nullptr;
|
||||
}
|
||||
|
||||
@@ -246,17 +245,11 @@ public:
|
||||
bool IsRealTime() const { return mRealTime; }
|
||||
|
||||
size_t SizeOfVideoQueue() {
|
||||
if (mReader) {
|
||||
return mReader->SizeOfVideoQueueInBytes();
|
||||
}
|
||||
return 0;
|
||||
return mReader->SizeOfVideoQueueInBytes();
|
||||
}
|
||||
|
||||
size_t SizeOfAudioQueue() {
|
||||
if (mReader) {
|
||||
return mReader->SizeOfAudioQueueInBytes();
|
||||
}
|
||||
return 0;
|
||||
return mReader->SizeOfAudioQueueInBytes();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -348,7 +341,7 @@ private:
|
||||
|
||||
// Discard audio/video data that are already played by MSG.
|
||||
void DiscardStreamData();
|
||||
bool HaveEnoughDecodedAudio(int64_t aAmpleAudioUSecs);
|
||||
bool HaveEnoughDecodedAudio();
|
||||
bool HaveEnoughDecodedVideo();
|
||||
|
||||
// Returns true if the state machine has shutdown or is in the process of
|
||||
@@ -362,7 +355,7 @@ private:
|
||||
// TODO: Those callback function may receive demuxed-only data.
|
||||
// Need to figure out a suitable API name for this case.
|
||||
void OnAudioDecoded(MediaData* aAudioSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample);
|
||||
void OnVideoDecoded(MediaData* aVideoSample, TimeStamp aDecodeStartTime);
|
||||
void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason);
|
||||
void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
@@ -390,7 +383,6 @@ protected:
|
||||
// aSample must not be null.
|
||||
|
||||
void Push(MediaData* aSample, MediaData::Type aSampleType);
|
||||
void PushFront(MediaData* aSample, MediaData::Type aSampleType);
|
||||
|
||||
void OnAudioPopped(const RefPtr<MediaData>& aSample);
|
||||
void OnVideoPopped(const RefPtr<MediaData>& aSample);
|
||||
@@ -528,9 +520,56 @@ protected:
|
||||
|
||||
void EnqueueFirstFrameLoadedEvent();
|
||||
|
||||
struct SeekJob {
|
||||
SeekJob() {}
|
||||
|
||||
SeekJob(SeekJob&& aOther) : mTarget(aOther.mTarget)
|
||||
{
|
||||
aOther.mTarget.Reset();
|
||||
mPromise = Move(aOther.mPromise);
|
||||
}
|
||||
|
||||
SeekJob& operator=(SeekJob&& aOther)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Exists());
|
||||
mTarget = aOther.mTarget;
|
||||
aOther.mTarget.Reset();
|
||||
mPromise = Move(aOther.mPromise);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool Exists()
|
||||
{
|
||||
MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
|
||||
return mTarget.IsValid();
|
||||
}
|
||||
|
||||
void Resolve(bool aAtEnd, const char* aCallSite)
|
||||
{
|
||||
mTarget.Reset();
|
||||
MediaDecoder::SeekResolveValue val(aAtEnd, mTarget.mEventVisibility);
|
||||
mPromise.Resolve(val, aCallSite);
|
||||
}
|
||||
|
||||
void RejectIfExists(const char* aCallSite)
|
||||
{
|
||||
mTarget.Reset();
|
||||
mPromise.RejectIfExists(true, aCallSite);
|
||||
}
|
||||
|
||||
~SeekJob()
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mTarget.IsValid());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromise.IsEmpty());
|
||||
}
|
||||
|
||||
SeekTarget mTarget;
|
||||
MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
|
||||
};
|
||||
|
||||
// Clears any previous seeking state and initiates a new see on the decoder.
|
||||
// The decoder monitor must be held.
|
||||
void InitiateSeek();
|
||||
void InitiateSeek(SeekJob aSeekJob);
|
||||
|
||||
nsresult DispatchAudioDecodeTaskIfNeeded();
|
||||
|
||||
@@ -662,138 +701,6 @@ private:
|
||||
// Used to dispatch another round schedule with specific target time.
|
||||
DelayedScheduler mDelayedScheduler;
|
||||
|
||||
// StartTimeRendezvous is a helper class that quarantines the first sample
|
||||
// until it gets a sample from both channels, such that we can be guaranteed
|
||||
// to know the start time by the time On{Audio,Video}Decoded is called.
|
||||
class StartTimeRendezvous {
|
||||
public:
|
||||
typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
|
||||
typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
|
||||
typedef MozPromise<bool, bool, /* isExclusive = */ false> HaveStartTimePromise;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StartTimeRendezvous);
|
||||
StartTimeRendezvous(AbstractThread* aOwnerThread, bool aHasAudio, bool aHasVideo,
|
||||
bool aForceZeroStartTime)
|
||||
: mOwnerThread(aOwnerThread)
|
||||
{
|
||||
if (aForceZeroStartTime) {
|
||||
mAudioStartTime.emplace(0);
|
||||
mVideoStartTime.emplace(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aHasAudio) {
|
||||
mAudioStartTime.emplace(INT64_MAX);
|
||||
}
|
||||
|
||||
if (!aHasVideo) {
|
||||
mVideoStartTime.emplace(INT64_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
mAudioStartTime = Some(mAudioStartTime.refOr(INT64_MAX));
|
||||
mVideoStartTime = Some(mVideoStartTime.refOr(INT64_MAX));
|
||||
mHaveStartTimePromise.RejectIfExists(false, __func__);
|
||||
}
|
||||
|
||||
RefPtr<HaveStartTimePromise> AwaitStartTime()
|
||||
{
|
||||
if (HaveStartTime()) {
|
||||
return HaveStartTimePromise::CreateAndResolve(true, __func__);
|
||||
}
|
||||
return mHaveStartTimePromise.Ensure(__func__);
|
||||
}
|
||||
|
||||
template<typename PromiseType>
|
||||
struct PromiseSampleType {
|
||||
typedef typename PromiseType::ResolveValueType::element_type Type;
|
||||
};
|
||||
|
||||
template<typename PromiseType, MediaData::Type SampleType>
|
||||
RefPtr<PromiseType> ProcessFirstSample(typename PromiseSampleType<PromiseType>::Type* aData)
|
||||
{
|
||||
typedef typename PromiseSampleType<PromiseType>::Type DataType;
|
||||
typedef typename PromiseType::Private PromisePrivate;
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
|
||||
MaybeSetChannelStartTime<SampleType>(aData->mTime);
|
||||
|
||||
RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
|
||||
RefPtr<DataType> data = aData;
|
||||
RefPtr<StartTimeRendezvous> self = this;
|
||||
AwaitStartTime()->Then(mOwnerThread, __func__,
|
||||
[p, data, self] () -> void {
|
||||
MOZ_ASSERT(self->mOwnerThread->IsCurrentThreadIn());
|
||||
p->Resolve(data, __func__);
|
||||
},
|
||||
[p] () -> void { p->Reject(MediaDecoderReader::CANCELED, __func__); });
|
||||
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
template<MediaData::Type SampleType>
|
||||
void FirstSampleRejected(MediaDecoderReader::NotDecodedReason aReason)
|
||||
{
|
||||
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
|
||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
||||
mHaveStartTimePromise.RejectIfExists(false, __func__);
|
||||
} else if (aReason == MediaDecoderReader::END_OF_STREAM) {
|
||||
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,
|
||||
("StartTimeRendezvous=%p SampleType(%d) Has no samples.", this, SampleType));
|
||||
MaybeSetChannelStartTime<SampleType>(INT64_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
bool HaveStartTime() { return mAudioStartTime.isSome() && mVideoStartTime.isSome(); }
|
||||
int64_t StartTime()
|
||||
{
|
||||
int64_t time = std::min(mAudioStartTime.ref(), mVideoStartTime.ref());
|
||||
return time == INT64_MAX ? 0 : time;
|
||||
}
|
||||
private:
|
||||
virtual ~StartTimeRendezvous() {}
|
||||
|
||||
template<MediaData::Type SampleType>
|
||||
void MaybeSetChannelStartTime(int64_t aStartTime)
|
||||
{
|
||||
if (ChannelStartTime(SampleType).isSome()) {
|
||||
// If we're initialized with aForceZeroStartTime=true, the channel start
|
||||
// times are already set.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_LOG(gMediaDecoderLog, LogLevel::Debug,
|
||||
("StartTimeRendezvous=%p Setting SampleType(%d) start time to %lld",
|
||||
this, SampleType, aStartTime));
|
||||
|
||||
ChannelStartTime(SampleType).emplace(aStartTime);
|
||||
if (HaveStartTime()) {
|
||||
mHaveStartTimePromise.ResolveIfExists(true, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<int64_t>& ChannelStartTime(MediaData::Type aType)
|
||||
{
|
||||
return aType == MediaData::AUDIO_DATA ? mAudioStartTime : mVideoStartTime;
|
||||
}
|
||||
|
||||
MozPromiseHolder<HaveStartTimePromise> mHaveStartTimePromise;
|
||||
RefPtr<AbstractThread> mOwnerThread;
|
||||
Maybe<int64_t> mAudioStartTime;
|
||||
Maybe<int64_t> mVideoStartTime;
|
||||
};
|
||||
RefPtr<StartTimeRendezvous> mStartTimeRendezvous;
|
||||
|
||||
bool HaveStartTime() { return mStartTimeRendezvous && mStartTimeRendezvous->HaveStartTime(); }
|
||||
int64_t StartTime() { return mStartTimeRendezvous->StartTime(); }
|
||||
|
||||
// Time at which the last video sample was requested. If it takes too long
|
||||
// before the sample arrives, we will increase the amount of audio we buffer.
|
||||
// This is necessary for legacy synchronous decoders to prevent underruns.
|
||||
TimeStamp mVideoDecodeStartTime;
|
||||
|
||||
// Queue of audio frames. This queue is threadsafe, and is accessed from
|
||||
// the audio, decoder, state machine, and main threads.
|
||||
MediaQueue<MediaData> mAudioQueue;
|
||||
@@ -840,50 +747,9 @@ private:
|
||||
mNextPlayState == MediaDecoder::PLAY_STATE_PLAYING;
|
||||
}
|
||||
|
||||
struct SeekJob {
|
||||
void Steal(SeekJob& aOther)
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!Exists());
|
||||
mTarget = aOther.mTarget;
|
||||
aOther.mTarget.Reset();
|
||||
mPromise = Move(aOther.mPromise);
|
||||
}
|
||||
|
||||
bool Exists()
|
||||
{
|
||||
MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty());
|
||||
return mTarget.IsValid();
|
||||
}
|
||||
|
||||
void Resolve(bool aAtEnd, const char* aCallSite)
|
||||
{
|
||||
mTarget.Reset();
|
||||
MediaDecoder::SeekResolveValue val(aAtEnd, mTarget.mEventVisibility);
|
||||
mPromise.Resolve(val, aCallSite);
|
||||
}
|
||||
|
||||
void RejectIfExists(const char* aCallSite)
|
||||
{
|
||||
mTarget.Reset();
|
||||
mPromise.RejectIfExists(true, aCallSite);
|
||||
}
|
||||
|
||||
~SeekJob()
|
||||
{
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mTarget.IsValid());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mPromise.IsEmpty());
|
||||
}
|
||||
|
||||
SeekTarget mTarget;
|
||||
MozPromiseHolder<MediaDecoder::SeekPromise> mPromise;
|
||||
};
|
||||
|
||||
// Queued seek - moves to mPendingSeek when DecodeFirstFrame completes.
|
||||
// Queued seek - moves to mCurrentSeek when DecodeFirstFrame completes.
|
||||
SeekJob mQueuedSeek;
|
||||
|
||||
// Position to seek to in microseconds when the seek state transition occurs.
|
||||
SeekJob mPendingSeek;
|
||||
|
||||
// The position that we're currently seeking to.
|
||||
SeekJob mCurrentSeek;
|
||||
|
||||
@@ -895,7 +761,9 @@ private:
|
||||
|
||||
// The reader, don't call its methods with the decoder monitor held.
|
||||
// This is created in the state machine's constructor.
|
||||
RefPtr<MediaDecoderReader> mReader;
|
||||
const RefPtr<MediaDecoderReader> mReader;
|
||||
|
||||
const RefPtr<MediaDecoderReaderWrapper> mReaderWrapper;
|
||||
|
||||
// The end time of the last audio frame that's been pushed onto the media sink
|
||||
// in microseconds. This will approximately be the end time
|
||||
|
||||
@@ -78,6 +78,8 @@ skip-if = true # bug 1182946
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekNoData_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekedEvent_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SeekTwice_mp4.html]
|
||||
skip-if = ((os == "win" && os_version == "5.1") || (os != "win" && os != "mac")) # Only supported on osx and vista+
|
||||
[test_SetModeThrows.html]
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>MSE: Check that seeked event is fired prior loadeddata</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="mediasource.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
runWithMSE(function(ms, el) {
|
||||
el.controls = true;
|
||||
el._seeked = false;
|
||||
el._loadeddata = false;
|
||||
el._playing = false;
|
||||
el.addEventListener("seeked", function() {
|
||||
ok(true, "got seeked event");
|
||||
is(el._loadeddata, false, "can't have received loadeddata prior seeked");
|
||||
is(el._playing, false, "can't be playing prior seeked");
|
||||
el._seeked = true;
|
||||
});
|
||||
el.addEventListener("loadeddata", function() {
|
||||
ok(true, "got loadeddata event");
|
||||
is(el._seeked, true, "must have received seeked prior loadeddata");
|
||||
is(el._playing, false, "can't be playing prior playing");
|
||||
el._loadeddata = true;
|
||||
});
|
||||
el.addEventListener("playing", function() {
|
||||
ok(true, "got playing");
|
||||
is(el._seeked, true, "must have received seeked prior playing");
|
||||
is(el._loadeddata, true, "must have received loadeddata prior playing");
|
||||
el._playing = true;
|
||||
});
|
||||
once(ms, 'sourceopen').then(function() {
|
||||
ok(true, "Receive a sourceopen event");
|
||||
var videosb = ms.addSourceBuffer("video/mp4");
|
||||
is(el.readyState, el.HAVE_NOTHING, "readyState is HAVE_NOTHING");
|
||||
fetchAndLoad(videosb, 'bipbop/bipbop_video', ['init'], '.mp4')
|
||||
.then(once.bind(null, el, "loadedmetadata"))
|
||||
.then(function() {
|
||||
el.play();
|
||||
videosb.timestampOffset = 2;
|
||||
is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
|
||||
// Load [2, 3.606).
|
||||
var promises = [];
|
||||
promises.push(once(el, "play"));
|
||||
promises.push(fetchAndLoad(videosb, 'bipbop/bipbop_video', ['1'], '.m4s'));
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function() {
|
||||
return fetchAndLoad(videosb, 'bipbop/bipbop_video', ['2'], '.m4s');
|
||||
})
|
||||
.then(function() {
|
||||
is(el.readyState, el.HAVE_METADATA, "readyState is HAVE_METADATA");
|
||||
el.currentTime = 2;
|
||||
var promises = [];
|
||||
promises.push(once(el, "seeked"));
|
||||
promises.push(once(el, "playing"));
|
||||
return Promise.all(promises);
|
||||
})
|
||||
.then(function() {
|
||||
ok(true, "completed seek");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -122,7 +122,7 @@ nsXBLResourceLoader::LoadResources(bool* aResult)
|
||||
// Passing nullptr for pretty much everything -- cause we don't care!
|
||||
// XXX: initialDocumentURI is nullptr!
|
||||
RefPtr<imgRequestProxy> req;
|
||||
nsContentUtils::LoadImage(url, doc, docPrincipal, docURL,
|
||||
nsContentUtils::LoadImage(url, doc, doc, docPrincipal, docURL,
|
||||
doc->GetReferrerPolicy(), nullptr,
|
||||
nsIRequest::LOAD_BACKGROUND, EmptyString(),
|
||||
getter_AddRefs(req));
|
||||
|
||||
@@ -292,7 +292,7 @@ nsContextMenuInfo::GetBackgroundImageRequestInternal(nsIDOMNode* aDOMNode,
|
||||
|
||||
return il->LoadImage(bgUri, nullptr, nullptr,
|
||||
doc->GetReferrerPolicy(), principal, nullptr,
|
||||
nullptr, nullptr, nsIRequest::LOAD_NORMAL,
|
||||
nullptr, nullptr, nullptr, nsIRequest::LOAD_NORMAL,
|
||||
nullptr, nsIContentPolicy::TYPE_INTERNAL_IMAGE,
|
||||
EmptyString(), aRequest);
|
||||
}
|
||||
|
||||
+11
-7
@@ -2071,6 +2071,8 @@ imgLoader::LoadImageXPCOM(nsIURI* aURI,
|
||||
}
|
||||
imgRequestProxy* proxy;
|
||||
ReferrerPolicy refpol = ReferrerPolicyFromString(aReferrerPolicy);
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aCX);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(aCX);
|
||||
nsresult rv = LoadImage(aURI,
|
||||
aInitialDocumentURI,
|
||||
aReferrerURI,
|
||||
@@ -2078,7 +2080,8 @@ imgLoader::LoadImageXPCOM(nsIURI* aURI,
|
||||
aLoadingPrincipal,
|
||||
aLoadGroup,
|
||||
aObserver,
|
||||
aCX,
|
||||
node,
|
||||
doc,
|
||||
aLoadFlags,
|
||||
aCacheKey,
|
||||
aContentPolicyType,
|
||||
@@ -2096,7 +2099,8 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX,
|
||||
nsINode *aContext,
|
||||
nsIDocument* aLoadingDocument,
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
@@ -2175,13 +2179,13 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
// XXX For now ignore aCacheKey. We will need it in the future
|
||||
// for correctly dealing with image load requests that are a result
|
||||
// of post data.
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aCX);
|
||||
nsCOMPtr<nsIDOMDocument> doc = do_QueryInterface(aLoadingDocument);
|
||||
ImageCacheKey key(aURI, doc);
|
||||
imgCacheTable& cache = GetCache(key);
|
||||
|
||||
if (cache.Get(key, getter_AddRefs(entry)) && entry) {
|
||||
if (ValidateEntry(entry, aURI, aInitialDocumentURI, aReferrerURI,
|
||||
aReferrerPolicy, aLoadGroup, aObserver, aCX,
|
||||
aReferrerPolicy, aLoadGroup, aObserver, aLoadingDocument,
|
||||
requestFlags, aContentPolicyType, true, _retval,
|
||||
aLoadingPrincipal, corsmode)) {
|
||||
request = entry->GetRequest();
|
||||
@@ -2232,7 +2236,7 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
requestFlags,
|
||||
aContentPolicyType,
|
||||
aLoadingPrincipal,
|
||||
aCX);
|
||||
aContext);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -2250,7 +2254,7 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
nsCOMPtr<nsILoadGroup> channelLoadGroup;
|
||||
newChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
|
||||
request->Init(aURI, aURI, /* aHadInsecureRedirect = */ false,
|
||||
channelLoadGroup, newChannel, entry, aCX,
|
||||
channelLoadGroup, newChannel, entry, aLoadingDocument,
|
||||
aLoadingPrincipal, corsmode, aReferrerPolicy);
|
||||
|
||||
// Add the initiator type for this image load
|
||||
@@ -2322,7 +2326,7 @@ imgLoader::LoadImage(nsIURI* aURI,
|
||||
// URL maps to the same image on a page) if we load the same image in a
|
||||
// different tab (see bug 528003), because its load id will get re-set, and
|
||||
// that'll cause us to validate over the network.
|
||||
request->SetLoadId(aCX);
|
||||
request->SetLoadId(aLoadingDocument);
|
||||
|
||||
LOG_MSG(gImgLog, "imgLoader::LoadImage", "creating proxy request.");
|
||||
rv = CreateNewProxyForRequest(request, aLoadGroup, aObserver,
|
||||
|
||||
+2
-1
@@ -252,7 +252,8 @@ public:
|
||||
nsIPrincipal* aLoadingPrincipal,
|
||||
nsILoadGroup* aLoadGroup,
|
||||
imgINotificationObserver* aObserver,
|
||||
nsISupports* aCX,
|
||||
nsINode* aContext,
|
||||
nsIDocument* aLoadingDocument,
|
||||
nsLoadFlags aLoadFlags,
|
||||
nsISupports* aCacheKey,
|
||||
nsContentPolicyType aContentPolicyType,
|
||||
|
||||
@@ -61,6 +61,14 @@ JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn,
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_Init(void);
|
||||
|
||||
/**
|
||||
* A variant of JS_Init. On success it returns nullptr. On failure it returns a
|
||||
* pointer to a string literal that describes how initialization failed, which
|
||||
* can be useful for debugging purposes.
|
||||
*/
|
||||
extern JS_PUBLIC_API(const char*)
|
||||
JS_InitWithFailureDiagnostic(void);
|
||||
|
||||
/**
|
||||
* Destroy free-standing resources allocated by SpiderMonkey, not associated
|
||||
* with any runtime, context, or other structure.
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "vm/Debugger-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
using namespace js::wasm;
|
||||
|
||||
using mozilla::CheckedInt;
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "gc/Tracer.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::frontend;
|
||||
|
||||
@@ -23,6 +23,9 @@ ion/bug787921.js
|
||||
ion/bug977966.js
|
||||
parallel/alloc-many-objs.js
|
||||
parallel/alloc-too-many-objs.js
|
||||
parser/bug-1263881-1.js
|
||||
parser/bug-1263881-2.js
|
||||
parser/bug-1263881-3.js
|
||||
saved-stacks/bug-1006876-too-much-recursion.js
|
||||
self-test/assertDeepEq.js
|
||||
sunspider/check-string-unpack-code.js
|
||||
|
||||
@@ -346,12 +346,16 @@ BytecodeCompiler::prepareAndEmitTree(ParseNode** ppn)
|
||||
{
|
||||
if (!FoldConstants(cx, ppn, parser.ptr()) ||
|
||||
!NameFunctions(cx, *ppn) ||
|
||||
!emitter->updateLocalsToFrameSlots() ||
|
||||
!emitter->emitTree(*ppn))
|
||||
!emitter->updateLocalsToFrameSlots())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
emitter->setFunctionBodyEndPos((*ppn)->pn_pos);
|
||||
|
||||
if (!emitter->emitTree(*ppn))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -846,7 +850,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
|
||||
MOZ_ASSERT(!options.forEval);
|
||||
BytecodeEmitter bce(/* parent = */ nullptr, &parser, pn->pn_funbox, script, lazy,
|
||||
/* insideEval = */ false, /* evalCaller = */ nullptr,
|
||||
/* insideNonGlobalEval = */ false, options.lineno,
|
||||
/* insideNonGlobalEval = */ false, pn->pn_pos,
|
||||
BytecodeEmitter::LazyFunction);
|
||||
if (!bce.init())
|
||||
return false;
|
||||
|
||||
@@ -143,12 +143,27 @@ BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
|
||||
insideEval(insideEval),
|
||||
insideNonGlobalEval(insideNonGlobalEval),
|
||||
insideModule(false),
|
||||
emitterMode(emitterMode)
|
||||
emitterMode(emitterMode),
|
||||
functionBodyEndPosSet(false)
|
||||
{
|
||||
MOZ_ASSERT_IF(evalCaller, insideEval);
|
||||
MOZ_ASSERT_IF(emitterMode == LazyFunction, lazyScript);
|
||||
}
|
||||
|
||||
BytecodeEmitter::BytecodeEmitter(BytecodeEmitter* parent,
|
||||
Parser<FullParseHandler>* parser, SharedContext* sc,
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, TokenPos bodyPosition,
|
||||
EmitterMode emitterMode)
|
||||
: BytecodeEmitter(parent, parser, sc, script, lazyScript, insideEval,
|
||||
evalCaller, insideNonGlobalEval,
|
||||
parser->tokenStream.srcCoords.lineNum(bodyPosition.begin),
|
||||
emitterMode)
|
||||
{
|
||||
setFunctionBodyEndPos(bodyPosition);
|
||||
}
|
||||
|
||||
bool
|
||||
BytecodeEmitter::init()
|
||||
{
|
||||
@@ -2820,8 +2835,13 @@ BytecodeEmitter::emitElemOperands(ParseNode* pn, EmitElemOption opts)
|
||||
if (!emitTree(pn->pn_right))
|
||||
return false;
|
||||
|
||||
if (opts == EmitElemOption::Set && !emit2(JSOP_PICK, 2))
|
||||
return false;
|
||||
if (opts == EmitElemOption::Set) {
|
||||
if (!emit2(JSOP_PICK, 2))
|
||||
return false;
|
||||
} else if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
|
||||
if (!emit1(JSOP_TOID))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2840,8 +2860,10 @@ BytecodeEmitter::emitSuperElemOperands(ParseNode* pn, EmitElemOption opts)
|
||||
|
||||
// We need to convert the key to an object id first, so that we do not do
|
||||
// it inside both the GETELEM and the SETELEM.
|
||||
if (opts == EmitElemOption::IncDec && !emit1(JSOP_TOID))
|
||||
return false;
|
||||
if (opts == EmitElemOption::IncDec || opts == EmitElemOption::CompoundAssign) {
|
||||
if (!emit1(JSOP_TOID))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitGetThisForSuperBase(pn->pn_left))
|
||||
return false;
|
||||
@@ -2913,6 +2935,9 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
|
||||
|
||||
bool isSuper = pn->pn_kid->as<PropertyByValue>().isSuper();
|
||||
|
||||
// We need to convert the key to an object id first, so that we do not do
|
||||
// it inside both the GETELEM and the SETELEM. This is done by
|
||||
// emit(Super)ElemOperands.
|
||||
if (isSuper) {
|
||||
if (!emitSuperElemOperands(pn->pn_kid, EmitElemOption::IncDec))
|
||||
return false;
|
||||
@@ -2936,12 +2961,7 @@ BytecodeEmitter::emitElemIncDec(ParseNode* pn)
|
||||
return false;
|
||||
getOp = JSOP_GETELEM_SUPER;
|
||||
} else {
|
||||
// We need to convert the key to an object id first, so that we do not do
|
||||
// it inside both the GETELEM and the SETELEM. In the super case, this is
|
||||
// done by emitSuperElemOperands.
|
||||
// OBJ KEY*
|
||||
if (!emit1(JSOP_TOID)) // OBJ KEY
|
||||
return false;
|
||||
// OBJ KEY
|
||||
if (!emit1(JSOP_DUP2)) // OBJ KEY OBJ KEY
|
||||
return false;
|
||||
getOp = JSOP_GETELEM;
|
||||
@@ -3598,9 +3618,13 @@ BytecodeEmitter::emitFunctionScript(ParseNode* body)
|
||||
switchToMain();
|
||||
}
|
||||
|
||||
setFunctionBodyEndPos(body->pn_pos);
|
||||
if (!emitTree(body))
|
||||
return false;
|
||||
|
||||
if (!updateSourceCoordNotes(body->pn_pos.end))
|
||||
return false;
|
||||
|
||||
if (sc->isFunctionBox()) {
|
||||
if (sc->asFunctionBox()->isGenerator()) {
|
||||
// If we fall off the end of a generator, do a final yield.
|
||||
@@ -3700,6 +3724,7 @@ BytecodeEmitter::emitModuleScript(ParseNode* body)
|
||||
// may walk the scope chain of currently compiling scripts.
|
||||
JSScript::linkToModuleFromEmitter(cx, script, modulebox);
|
||||
|
||||
setFunctionBodyEndPos(body->pn_pos);
|
||||
if (!emitTree(body))
|
||||
return false;
|
||||
|
||||
@@ -4601,20 +4626,20 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp op, ParseNode* rhs)
|
||||
if (!makeAtomIndex(lhs->pn_atom, &atomIndex))
|
||||
return false;
|
||||
break;
|
||||
case PNK_ELEM:
|
||||
case PNK_ELEM: {
|
||||
MOZ_ASSERT(lhs->isArity(PN_BINARY));
|
||||
EmitElemOption opt = op == JSOP_NOP ? EmitElemOption::Get : EmitElemOption::CompoundAssign;
|
||||
if (lhs->as<PropertyByValue>().isSuper()) {
|
||||
if (!emitSuperElemOperands(lhs))
|
||||
if (!emitSuperElemOperands(lhs, opt))
|
||||
return false;
|
||||
offset += 3;
|
||||
} else {
|
||||
if (!emitTree(lhs->pn_left))
|
||||
return false;
|
||||
if (!emitTree(lhs->pn_right))
|
||||
if (!emitElemOperands(lhs, opt))
|
||||
return false;
|
||||
offset += 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
break;
|
||||
@@ -6425,10 +6450,9 @@ BytecodeEmitter::emitFunction(ParseNode* pn, bool needsProto)
|
||||
|
||||
script->bindings = funbox->bindings;
|
||||
|
||||
uint32_t lineNum = parser->tokenStream.srcCoords.lineNum(pn->pn_pos.begin);
|
||||
BytecodeEmitter bce2(this, parser, funbox, script, /* lazyScript = */ nullptr,
|
||||
insideEval, evalCaller,
|
||||
insideNonGlobalEval, lineNum, emitterMode);
|
||||
insideNonGlobalEval, pn->pn_pos, emitterMode);
|
||||
if (!bce2.init())
|
||||
return false;
|
||||
|
||||
@@ -6799,6 +6823,13 @@ BytecodeEmitter::emitReturn(ParseNode* pn)
|
||||
return false;
|
||||
}
|
||||
|
||||
// We know functionBodyEndPos is set because "return" is only
|
||||
// valid in a function, and so we've passed through
|
||||
// emitFunctionScript.
|
||||
MOZ_ASSERT(functionBodyEndPosSet);
|
||||
if (!updateSourceCoordNotes(functionBodyEndPos))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* EmitNonLocalJumpFixup may add fixup bytecode to close open try
|
||||
* blocks having finally clauses and to exit intermingled let blocks.
|
||||
|
||||
@@ -232,6 +232,11 @@ struct BytecodeEmitter
|
||||
|
||||
const EmitterMode emitterMode;
|
||||
|
||||
// The end location of a function body that is being emitted.
|
||||
uint32_t functionBodyEndPos;
|
||||
// Whether functionBodyEndPos was set.
|
||||
bool functionBodyEndPosSet;
|
||||
|
||||
/*
|
||||
* Note that BytecodeEmitters are magic: they own the arena "top-of-stack"
|
||||
* space above their tempMark points. This means that you cannot alloc from
|
||||
@@ -242,6 +247,14 @@ struct BytecodeEmitter
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, uint32_t lineNum, EmitterMode emitterMode = Normal);
|
||||
|
||||
// An alternate constructor that uses a TokenPos for the starting
|
||||
// line and that sets functionBodyEndPos as well.
|
||||
BytecodeEmitter(BytecodeEmitter* parent, Parser<FullParseHandler>* parser, SharedContext* sc,
|
||||
HandleScript script, Handle<LazyScript*> lazyScript,
|
||||
bool insideEval, HandleScript evalCaller,
|
||||
bool insideNonGlobalEval, TokenPos bodyPosition, EmitterMode emitterMode = Normal);
|
||||
|
||||
bool init();
|
||||
bool updateLocalsToFrameSlots();
|
||||
|
||||
@@ -302,6 +315,11 @@ struct BytecodeEmitter
|
||||
unsigned currentLine() const { return current->currentLine; }
|
||||
unsigned lastColumn() const { return current->lastColumn; }
|
||||
|
||||
void setFunctionBodyEndPos(TokenPos pos) {
|
||||
functionBodyEndPos = pos.end;
|
||||
functionBodyEndPosSet = true;
|
||||
}
|
||||
|
||||
bool reportError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictWarning(ParseNode* pn, unsigned errorNumber, ...);
|
||||
bool reportStrictModeError(ParseNode* pn, unsigned errorNumber, ...);
|
||||
@@ -519,7 +537,7 @@ struct BytecodeEmitter
|
||||
// Emit bytecode to put operands for a JSOP_GETELEM/CALLELEM/SETELEM/DELELEM
|
||||
// opcode onto the stack in the right order. In the case of SETELEM, the
|
||||
// value to be assigned must already be pushed.
|
||||
enum class EmitElemOption { Get, Set, Call, IncDec };
|
||||
enum class EmitElemOption { Get, Set, Call, IncDec, CompoundAssign };
|
||||
bool emitElemOperands(ParseNode* pn, EmitElemOption opts);
|
||||
|
||||
bool emitElemOpBase(JSOp op);
|
||||
|
||||
@@ -94,7 +94,9 @@ template <>
|
||||
bool
|
||||
ParseContext<FullParseHandler>::checkLocalsOverflow(TokenStream& ts)
|
||||
{
|
||||
if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT) {
|
||||
if (vars_.length() + bodyLevelLexicals_.length() >= LOCALNO_LIMIT ||
|
||||
bodyLevelLexicals_.length() >= Bindings::BODY_LEVEL_LEXICAL_LIMIT)
|
||||
{
|
||||
ts.reportError(JSMSG_TOO_MANY_LOCALS);
|
||||
return false;
|
||||
}
|
||||
@@ -2331,8 +2333,9 @@ Parser<FullParseHandler>::bindBodyLevelFunctionName(HandlePropertyName funName,
|
||||
MOZ_ASSERT(!dn->isUsed());
|
||||
MOZ_ASSERT(dn->isDefn());
|
||||
|
||||
if (dn->kind() == Definition::CONSTANT || dn->kind() == Definition::LET)
|
||||
return reportRedeclaration(nullptr, Definition::VAR, funName);
|
||||
Definition::Kind kind = dn->kind();
|
||||
if (kind == Definition::CONSTANT || kind == Definition::LET || kind == Definition::IMPORT)
|
||||
return reportRedeclaration(nullptr, kind, funName);
|
||||
|
||||
/*
|
||||
* Body-level function statements are effectively variable
|
||||
@@ -2342,7 +2345,7 @@ Parser<FullParseHandler>::bindBodyLevelFunctionName(HandlePropertyName funName,
|
||||
* the function's binding (which is mutable), so turn any existing
|
||||
* declaration into a use.
|
||||
*/
|
||||
if (dn->kind() == Definition::ARG) {
|
||||
if (kind == Definition::ARG) {
|
||||
// The exception to the above comment is when the function
|
||||
// has the same name as an argument. Then the argument node
|
||||
// remains a definition. But change the function node pn so
|
||||
@@ -2751,7 +2754,10 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
|
||||
Node pn = noSubstitutionTemplate();
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
Node nodeList = handler.newList(PNK_TEMPLATE_STRING_LIST, pn);
|
||||
if (!nodeList)
|
||||
return null();
|
||||
|
||||
TokenKind tt;
|
||||
do {
|
||||
@@ -3212,6 +3218,8 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
|
||||
return false;
|
||||
}
|
||||
|
||||
handler.setEndPosition(body, pos().begin);
|
||||
|
||||
return finishFunctionDefinition(pn, funbox, body);
|
||||
}
|
||||
|
||||
@@ -4016,7 +4024,7 @@ HasOuterLexicalBinding(ParseContext<ParseHandler>* pc, StmtInfoPC* stmt, HandleA
|
||||
while (stmt->enclosingScope) {
|
||||
stmt = LexicalLookup(pc, atom, stmt->enclosingScope);
|
||||
if (!stmt)
|
||||
return false;
|
||||
break;
|
||||
if (stmt->type == StmtType::BLOCK)
|
||||
return true;
|
||||
}
|
||||
@@ -7584,8 +7592,11 @@ Parser<ParseHandler>::expr(InHandling inHandling, YieldHandling yieldHandling,
|
||||
|
||||
// We begin by checking for an outer pending error since it would
|
||||
// have occurred first.
|
||||
if (possibleError->checkForExprErrors())
|
||||
possibleErrorInner.checkForExprErrors();
|
||||
if (possibleError && !possibleError->checkForExprErrors())
|
||||
return null();
|
||||
|
||||
// Go ahead and report the inner error.
|
||||
possibleErrorInner.checkForExprErrors();
|
||||
return null();
|
||||
}
|
||||
handler.addList(seq, pn);
|
||||
|
||||
+18
-4
@@ -470,11 +470,25 @@ class HeapPtr : public WriteBarrieredBase<T>
|
||||
};
|
||||
|
||||
/*
|
||||
* A pre- and post-barriered heap pointer, for use inside the JS engine.
|
||||
* A pre- and post-barriered heap pointer, for use inside the JS engine. These
|
||||
* heap pointers can be stored in C++ containers like GCVector and GCHashMap.
|
||||
*
|
||||
* Unlike HeapPtr<T>, it can be used in memory that is not managed by the GC,
|
||||
* i.e. in C++ containers. It is, however, somewhat slower, so should only be
|
||||
* used in contexts where this ability is necessary.
|
||||
* The GC sometimes keeps pointers to pointers to GC things --- for example, to
|
||||
* track references into the nursery. However, C++ containers like GCVector and
|
||||
* GCHashMap usually reserve the right to relocate their elements any time
|
||||
* they're modified, invalidating all pointers to the elements. RelocatablePtr
|
||||
* has a move constructor which knows how to keep the GC up to date if it is
|
||||
* moved to a new location.
|
||||
*
|
||||
* However, because of this additional communication with the GC, RelocatablePtr
|
||||
* is somewhat slower, so it should only be used in contexts where this ability
|
||||
* is necessary.
|
||||
*
|
||||
* Obviously, JSObjects, JSStrings, and the like get tenured and compacted, so
|
||||
* whatever pointers they contain get relocated, in the sense used here.
|
||||
* However, since the GC itself is moving those values, it takes care of its
|
||||
* internal pointers to those pointers itself. RelocatablePtr is only necessary
|
||||
* when the relocation would otherwise occur without the GC's knowledge.
|
||||
*/
|
||||
template <class T>
|
||||
class RelocatablePtr : public WriteBarrieredBase<T>
|
||||
|
||||
+13
-14
@@ -2154,6 +2154,7 @@ JSObject*
|
||||
js::TenuringTracer::moveToTenured(JSObject* src)
|
||||
{
|
||||
MOZ_ASSERT(IsInsideNursery(src));
|
||||
MOZ_ASSERT(!src->zone()->usedByExclusiveThread);
|
||||
|
||||
AllocKind dstKind = src->allocKindForTenure(nursery());
|
||||
Zone* zone = src->zone();
|
||||
@@ -2286,20 +2287,18 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind
|
||||
}
|
||||
}
|
||||
|
||||
if (src->getClass()->flags & JSCLASS_SKIP_NURSERY_FINALIZE) {
|
||||
if (src->is<InlineTypedObject>()) {
|
||||
InlineTypedObject::objectMovedDuringMinorGC(this, dst, src);
|
||||
} else if (src->is<UnboxedArrayObject>()) {
|
||||
tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
|
||||
} else if (src->is<ArgumentsObject>()) {
|
||||
tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src);
|
||||
} else if (JSObjectMovedOp op = dst->getClass()->extObjectMovedOp()) {
|
||||
op(dst, src);
|
||||
} else {
|
||||
// Objects with JSCLASS_SKIP_NURSERY_FINALIZE need to be handled above
|
||||
// to ensure any additional nursery buffers they hold are moved.
|
||||
MOZ_CRASH("Unhandled JSCLASS_SKIP_NURSERY_FINALIZE Class");
|
||||
}
|
||||
if (src->is<InlineTypedObject>()) {
|
||||
InlineTypedObject::objectMovedDuringMinorGC(this, dst, src);
|
||||
} else if (src->is<UnboxedArrayObject>()) {
|
||||
tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
|
||||
} else if (src->is<ArgumentsObject>()) {
|
||||
tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src);
|
||||
} else if (JSObjectMovedOp op = dst->getClass()->extObjectMovedOp()) {
|
||||
op(dst, src);
|
||||
} else if (src->getClass()->flags & JSCLASS_SKIP_NURSERY_FINALIZE) {
|
||||
// Objects with JSCLASS_SKIP_NURSERY_FINALIZE need to be handled above
|
||||
// to ensure any additional nursery buffers they hold are moved.
|
||||
MOZ_CRASH("Unhandled JSCLASS_SKIP_NURSERY_FINALIZE Class");
|
||||
}
|
||||
|
||||
return tenuredSize;
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#define gc_Policy_h
|
||||
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Marking.h"
|
||||
#include "js/GCPolicyAPI.h"
|
||||
|
||||
// Forward declare the types we're defining policies for. This file is
|
||||
@@ -17,6 +19,7 @@
|
||||
// will be available when we do template expansion, allowing for use of
|
||||
// static members in the underlying types. We cannot, however, use
|
||||
// static_assert to verify relations between types.
|
||||
class JSLinearString;
|
||||
namespace js {
|
||||
class AccessorShape;
|
||||
class ArgumentsObject;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
if (!('oomTest' in this))
|
||||
quit();
|
||||
function f(x) {
|
||||
oomTest(() => eval(x));
|
||||
}
|
||||
f("");
|
||||
f("");
|
||||
f(`eval([ "x = \`\${new Error.lineNumber}" ].join())`);
|
||||
@@ -0,0 +1,34 @@
|
||||
// Check that the line number reported at an onPop stop makes sense,
|
||||
// even when it happens on an "artificial" instruction.
|
||||
|
||||
var g = newGlobal();
|
||||
|
||||
// This bit of code arranges for the line number of the "artificial"
|
||||
// instruction to be something nonsensical -- the middle of a loop
|
||||
// which cannot be entered.
|
||||
g.eval(`function f() {
|
||||
debugger; // +0
|
||||
if(false) { // +1
|
||||
for(var b=0; b<0; b++) { // +2
|
||||
c = 2; // +3
|
||||
} // +4
|
||||
} // +5
|
||||
} // +6
|
||||
`);
|
||||
|
||||
var dbg = Debugger(g);
|
||||
|
||||
let debugLine;
|
||||
let foundLine;
|
||||
|
||||
dbg.onDebuggerStatement = function(frame) {
|
||||
debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
|
||||
frame.onPop = function(c) {
|
||||
foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
|
||||
};
|
||||
};
|
||||
|
||||
g.eval("f();\n");
|
||||
|
||||
// The stop should happen on the closing brace of the function.
|
||||
assertEq(foundLine == debugLine + 6, true);
|
||||
@@ -33,4 +33,4 @@ dbg.onDebuggerStatement = function(frame) {
|
||||
|
||||
g.f();
|
||||
|
||||
assertEq(foundLines, ",1,2,3,4,5,6,7,8,10");
|
||||
assertEq(foundLines, ",1,2,3,4,5,6,7,8,10,11");
|
||||
|
||||
@@ -65,7 +65,7 @@ testOne("testTryFinally",
|
||||
} finally { // +6
|
||||
} // +7
|
||||
nothing(); // +8
|
||||
`, "168");
|
||||
`, "1689");
|
||||
|
||||
// The same but without a finally clause.
|
||||
testOne("testTryCatch",
|
||||
@@ -74,7 +74,7 @@ testOne("testTryCatch",
|
||||
} catch (e) { // +6
|
||||
} // +7
|
||||
nothing(); // +8
|
||||
`, "18");
|
||||
`, "189");
|
||||
|
||||
// Test the instructions at the end of a "catch".
|
||||
testOne("testCatchFinally",
|
||||
@@ -85,7 +85,7 @@ testOne("testCatchFinally",
|
||||
} finally { // +6
|
||||
} // +7
|
||||
nothing(); // +8
|
||||
`, "168");
|
||||
`, "1689");
|
||||
|
||||
// The same but without a finally clause. This relies on a
|
||||
// SpiderMonkey extension, because otherwise there's no way to see
|
||||
@@ -98,7 +98,7 @@ testOne("testCatch",
|
||||
} catch (e) { // +6
|
||||
} // +7
|
||||
nothing(); // +8
|
||||
`, "18");
|
||||
`, "189");
|
||||
|
||||
// Test the instruction at the end of a "finally" clause.
|
||||
testOne("testFinally",
|
||||
@@ -107,7 +107,7 @@ testOne("testFinally",
|
||||
${bitOfCode}
|
||||
} // +6
|
||||
nothing(); // +7
|
||||
`, "17");
|
||||
`, "178");
|
||||
|
||||
// Test the instruction at the end of a "then" clause.
|
||||
testOne("testThen",
|
||||
@@ -116,7 +116,7 @@ testOne("testThen",
|
||||
} else { // +6
|
||||
} // +7
|
||||
nothing(); // +8
|
||||
`, "18");
|
||||
`, "189");
|
||||
|
||||
// Test the instructions leaving a switch block.
|
||||
testOne("testSwitch",
|
||||
@@ -126,4 +126,4 @@ testOne("testSwitch",
|
||||
${bitOfCode}
|
||||
} // +6
|
||||
nothing(); // +7
|
||||
`, "17");
|
||||
`, "178");
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Stepping over a not-taken "if" that is at the end of the function
|
||||
// should move to the end of the function, not somewhere in the body
|
||||
// of the "if".
|
||||
|
||||
var g = newGlobal();
|
||||
g.eval(`function f() { // 1
|
||||
var a,c; // 2
|
||||
debugger; // 3
|
||||
if(false) { // 4
|
||||
for(var b=0; b<0; b++) { // 5
|
||||
c = 2; // 6
|
||||
} // 7
|
||||
} // 8
|
||||
} // 9
|
||||
`);
|
||||
|
||||
var dbg = Debugger(g);
|
||||
var badStep = false;
|
||||
|
||||
dbg.onDebuggerStatement = function(frame) {
|
||||
let debugLine = frame.script.getOffsetLocation(frame.offset).lineNumber;
|
||||
assertEq(debugLine, 3);
|
||||
frame.onStep = function() {
|
||||
let foundLine = this.script.getOffsetLocation(this.offset).lineNumber;
|
||||
assertEq(foundLine <= 4 || foundLine >= 8, true);
|
||||
};
|
||||
};
|
||||
|
||||
g.eval("f();\n");
|
||||
@@ -0,0 +1,34 @@
|
||||
// Stepping through a function with a return statement should pause on
|
||||
// the closing brace of the function.
|
||||
|
||||
var g = newGlobal();
|
||||
var dbg = Debugger(g);
|
||||
var log;
|
||||
|
||||
function test(fnStr) {
|
||||
log = '';
|
||||
g.eval(fnStr);
|
||||
|
||||
dbg.onDebuggerStatement = function(frame) {
|
||||
frame.onStep = function() {
|
||||
let {lineNumber, isEntryPoint} = frame.script.getOffsetLocation(frame.offset);
|
||||
if (isEntryPoint) {
|
||||
log += lineNumber + ' ';
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
g.eval("f(23);");
|
||||
}
|
||||
|
||||
test("function f(x) {\n" + // 1
|
||||
" debugger;\n" + // 2
|
||||
" return 23 + x;\n" + // 3
|
||||
"}\n"); // 4
|
||||
assertEq(log, '3 4 ');
|
||||
|
||||
test("function f(x) {\n" + // 1
|
||||
" debugger;\n" + // 2
|
||||
" return;\n" + // 3
|
||||
"}\n"); // 4
|
||||
assertEq(log, '3 4 ');
|
||||
@@ -48,7 +48,7 @@ assertEq(Object.keys(offsets).length, 2);
|
||||
// have no effect on this one.
|
||||
doSingleStep = false;
|
||||
g.eval('t(0, 0, 0)');
|
||||
assertEq(Object.keys(offsets).length, 6);
|
||||
assertEq(Object.keys(offsets).length, 7);
|
||||
doSingleStep = true;
|
||||
|
||||
// Single-step in an eval frame. This should reach every line but the
|
||||
|
||||
@@ -16,4 +16,4 @@ Debugger(global).onDebuggerStatement = function (frame) {
|
||||
global.log = '';
|
||||
global.eval("function f(n) { for (var i = 0; i < n; ++i) log += '. '; log += '! '; } debugger;");
|
||||
global.f(3);
|
||||
assertEq(global.log, "25 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 69 ");
|
||||
assertEq(global.log, "25 32 44 . 39 32 44 . 39 32 44 . 39 32 57 ! 70 ");
|
||||
|
||||
@@ -16,7 +16,7 @@ Debugger(global).onDebuggerStatement = function (frame) {
|
||||
global.log = "";
|
||||
global.eval("function ppppp() { return 1; }");
|
||||
// 1 2 3 4
|
||||
// 0123456789012345678901234567890123456789012345678
|
||||
// 01234567890123456789012345678901234567890123456789
|
||||
global.eval("function f(){ 1 && ppppp(ppppp()) && new Error() } debugger;");
|
||||
global.f();
|
||||
|
||||
@@ -24,5 +24,5 @@ global.f();
|
||||
// 25 - Inner print()
|
||||
// 19 - Outer print()
|
||||
// 37 - new Error()
|
||||
// 48 - Exit the function body
|
||||
assertEq(global.log, "14 25 19 37 48 ");
|
||||
// 49 - Exit the function body
|
||||
assertEq(global.log, "14 25 19 37 49 ");
|
||||
|
||||
@@ -55,7 +55,9 @@ g.eval("/* Any copyright is dedicated to the Public Domain.\n" +
|
||||
" eval(\"42;\");\n" +
|
||||
" function foo() {}\n" +
|
||||
" if (true) {\n" +
|
||||
" foo();\n" + // <- this is +6 and must be within the extent
|
||||
" }\n" +
|
||||
"}");
|
||||
test(g.secondCall, 7);
|
||||
" foo();\n" +
|
||||
// The "missing" newline here is a trick to make a newline
|
||||
// source note come at the end. A real newline between the two
|
||||
// closing braces causes a setline note instead.
|
||||
" } }");
|
||||
test(g.secondCall, 8);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// |jit-test| --ion-pgo=on;
|
||||
|
||||
target = handler = {}
|
||||
for (p of[new Proxy(target, handler)])
|
||||
evaluate("foo()");
|
||||
function foo() {
|
||||
symbols = [Symbol]
|
||||
values = [NaN]
|
||||
for (comparator of[""])
|
||||
for (b of values) assertEq;
|
||||
for (comparator of[""])
|
||||
for (a of symbols)
|
||||
for (b of values) assertEq;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// |jit-test| module; error:SyntaxError
|
||||
import x from 'y';
|
||||
function x() {}
|
||||
@@ -0,0 +1,11 @@
|
||||
// |jit-test| error: SyntaxError
|
||||
let moduleRepo = {};
|
||||
setModuleResolveHook(function(module, specifier) {
|
||||
return moduleRepo[specifier];
|
||||
});
|
||||
moduleRepo['a'] = parseModule("export let a = 1;");
|
||||
let s = "";
|
||||
let max = 65536;
|
||||
for (let i = 0; i < max; i++)
|
||||
s += "import * as ns" + i + " from 'a';\n";
|
||||
parseModule(s);
|
||||
@@ -0,0 +1,6 @@
|
||||
// |jit-test| error: SyntaxError
|
||||
let s = "";
|
||||
let max = 65536;
|
||||
for (let i = 0; i < max; i++)
|
||||
s += "let ns" + i + " = "+ i +";\n";
|
||||
eval(s);
|
||||
@@ -0,0 +1,7 @@
|
||||
// |jit-test| error: SyntaxError
|
||||
let s = "function foo() {\n";
|
||||
let max = 65536;
|
||||
for (let i = 0; i < max; i++)
|
||||
s += "let ns" + i + " = "+ i +";\n";
|
||||
s += "};";
|
||||
eval(s);
|
||||
@@ -1909,7 +1909,8 @@ jit::RenumberBlocks(MIRGraph& graph)
|
||||
// A utility for code which deletes blocks. Renumber the remaining blocks,
|
||||
// recompute dominators, and optionally recompute AliasAnalysis dependencies.
|
||||
bool
|
||||
jit::AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAnalysis)
|
||||
jit::AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAnalysis,
|
||||
bool underValueNumberer)
|
||||
{
|
||||
// Renumber the blocks and clear out the old dominator info.
|
||||
size_t id = 0;
|
||||
@@ -1928,7 +1929,7 @@ jit::AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAn
|
||||
return false;
|
||||
}
|
||||
|
||||
AssertExtendedGraphCoherency(graph);
|
||||
AssertExtendedGraphCoherency(graph, underValueNumberer);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2556,7 +2557,7 @@ AssertResumePointDominatedByOperands(MResumePoint* resume)
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
jit::AssertExtendedGraphCoherency(MIRGraph& graph)
|
||||
jit::AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer)
|
||||
{
|
||||
// Checks the basic GraphCoherency but also other conditions that
|
||||
// do not hold immediately (such as the fact that critical edges
|
||||
@@ -2580,8 +2581,15 @@ jit::AssertExtendedGraphCoherency(MIRGraph& graph)
|
||||
MOZ_ASSERT(block->getSuccessor(i)->numPredecessors() == 1);
|
||||
|
||||
if (block->isLoopHeader()) {
|
||||
MOZ_ASSERT(block->numPredecessors() == 2);
|
||||
MBasicBlock* backedge = block->getPredecessor(1);
|
||||
if (underValueNumberer && block->numPredecessors() == 3) {
|
||||
// Fixup block.
|
||||
MOZ_ASSERT(block->getPredecessor(1)->numPredecessors() == 0);
|
||||
MOZ_ASSERT(graph.osrBlock(),
|
||||
"Fixup blocks should only exists if we have an osr block.");
|
||||
} else {
|
||||
MOZ_ASSERT(block->numPredecessors() == 2);
|
||||
}
|
||||
MBasicBlock* backedge = block->backedge();
|
||||
MOZ_ASSERT(backedge->id() >= block->id());
|
||||
MOZ_ASSERT(backedge->numSuccessors() == 1);
|
||||
MOZ_ASSERT(backedge->getSuccessor(0) == *block);
|
||||
|
||||
@@ -60,7 +60,8 @@ bool
|
||||
RenumberBlocks(MIRGraph& graph);
|
||||
|
||||
bool
|
||||
AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAnalysis);
|
||||
AccountForCFGChanges(MIRGenerator* mir, MIRGraph& graph, bool updateAliasAnalysis,
|
||||
bool underValueNumberer = false);
|
||||
|
||||
bool
|
||||
RemoveUnmarkedBlocks(MIRGenerator* mir, MIRGraph& graph, uint32_t numMarkedBlocks);
|
||||
@@ -81,7 +82,7 @@ void
|
||||
AssertGraphCoherency(MIRGraph& graph);
|
||||
|
||||
void
|
||||
AssertExtendedGraphCoherency(MIRGraph& graph);
|
||||
AssertExtendedGraphCoherency(MIRGraph& graph, bool underValueNumberer = false);
|
||||
|
||||
bool
|
||||
EliminateRedundantChecks(MIRGraph& graph);
|
||||
|
||||
@@ -429,7 +429,11 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
bool hasUniqueBackedge() const {
|
||||
MOZ_ASSERT(isLoopHeader());
|
||||
MOZ_ASSERT(numPredecessors() >= 2);
|
||||
return numPredecessors() == 2;
|
||||
if (numPredecessors() == 2)
|
||||
return true;
|
||||
if (numPredecessors() == 3) // fixup block added by ValueNumbering phase.
|
||||
return getPredecessor(1)->numPredecessors() == 0;
|
||||
return false;
|
||||
}
|
||||
MBasicBlock* backedge() const {
|
||||
MOZ_ASSERT(hasUniqueBackedge());
|
||||
@@ -476,6 +480,9 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||
}
|
||||
void unmark() {
|
||||
MOZ_ASSERT(mark_, "Unarking unmarked block");
|
||||
unmarkUnchecked();
|
||||
}
|
||||
void unmarkUnchecked() {
|
||||
mark_ = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -520,14 +520,12 @@ ValueNumberer::removePredecessorAndCleanUp(MBasicBlock* block, MBasicBlock* pred
|
||||
// If this is a loop header, test whether it will become an unreachable
|
||||
// loop, or whether it needs special OSR-related fixups.
|
||||
bool isUnreachableLoop = false;
|
||||
MBasicBlock* origBackedgeForOSRFixup = nullptr;
|
||||
if (block->isLoopHeader()) {
|
||||
if (block->loopPredecessor() == pred) {
|
||||
if (MOZ_UNLIKELY(hasNonDominatingPredecessor(block, pred))) {
|
||||
JitSpew(JitSpew_GVN, " "
|
||||
"Loop with header block%u is now only reachable through an "
|
||||
"OSR entry into the middle of the loop!!", block->id());
|
||||
origBackedgeForOSRFixup = block->backedge();
|
||||
} else {
|
||||
// Deleting the entry into the loop makes the loop unreachable.
|
||||
isUnreachableLoop = true;
|
||||
@@ -606,11 +604,6 @@ ValueNumberer::removePredecessorAndCleanUp(MBasicBlock* block, MBasicBlock* pred
|
||||
// Use the mark to note that we've already removed all its predecessors,
|
||||
// and we know it's unreachable.
|
||||
block->mark();
|
||||
} else if (MOZ_UNLIKELY(origBackedgeForOSRFixup != nullptr)) {
|
||||
// The loop is no only reachable through OSR into the middle. Fix it
|
||||
// up so that the CFG can remain valid.
|
||||
if (!fixupOSROnlyLoop(block, origBackedgeForOSRFixup))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1079,6 +1072,30 @@ ValueNumberer::visitGraph()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ValueNumberer::insertOSRFixups()
|
||||
{
|
||||
ReversePostorderIterator end(graph_.end());
|
||||
for (ReversePostorderIterator iter(graph_.begin()); iter != end; ) {
|
||||
MBasicBlock* block = *iter++;
|
||||
|
||||
// Only add fixup block above for loops which can be reached from OSR.
|
||||
if (!block->isLoopHeader())
|
||||
continue;
|
||||
|
||||
// If the loop header is not self-dominated, then this loop does not
|
||||
// have to deal with a second entry point, so there is no need to add a
|
||||
// second entry point with a fixup block.
|
||||
if (block->immediateDominator() != block)
|
||||
continue;
|
||||
|
||||
if (!fixupOSROnlyLoop(block, block->backedge()))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// OSR fixups serve the purpose of representing the non-OSR entry into a loop
|
||||
// when the only real entry is an OSR entry into the middle. However, if the
|
||||
// entry into the middle is subsequently folded away, the loop may actually
|
||||
@@ -1101,22 +1118,44 @@ bool ValueNumberer::cleanupOSRFixups()
|
||||
succ->mark();
|
||||
if (!worklist.append(succ))
|
||||
return false;
|
||||
} else if (succ->isLoopHeader() &&
|
||||
succ->loopPredecessor() == block &&
|
||||
succ->numPredecessors() == 3)
|
||||
{
|
||||
// Unmark fixup blocks if the loop predecessor is marked after
|
||||
// the loop header.
|
||||
succ->getPredecessor(1)->unmarkUnchecked();
|
||||
}
|
||||
}
|
||||
// The one special thing we do during this mark pass is to mark
|
||||
// loop predecessors of reachable blocks as reachable. These blocks are
|
||||
// the OSR fixups blocks which need to remain if the loop remains,
|
||||
// though they can be removed if the loop is removed.
|
||||
|
||||
// OSR fixup blocks are needed if and only if the loop header is
|
||||
// reachable from its backedge (via the OSR block) and not from its
|
||||
// original loop predecessor.
|
||||
//
|
||||
// Thus OSR fixup blocks are removed if the loop header is not
|
||||
// reachable, or if the loop header is reachable from both its backedge
|
||||
// and its original loop predecessor.
|
||||
if (block->isLoopHeader()) {
|
||||
MBasicBlock* pred = block->loopPredecessor();
|
||||
if (!pred->isMarked() && pred->numPredecessors() == 0) {
|
||||
MOZ_ASSERT(pred->numSuccessors() == 1,
|
||||
MBasicBlock* maybeFixupBlock = nullptr;
|
||||
if (block->numPredecessors() == 2) {
|
||||
maybeFixupBlock = block->getPredecessor(0);
|
||||
} else {
|
||||
MOZ_ASSERT(block->numPredecessors() == 3);
|
||||
if (!block->loopPredecessor()->isMarked())
|
||||
maybeFixupBlock = block->getPredecessor(1);
|
||||
}
|
||||
|
||||
if (maybeFixupBlock &&
|
||||
!maybeFixupBlock->isMarked() &&
|
||||
maybeFixupBlock->numPredecessors() == 0)
|
||||
{
|
||||
MOZ_ASSERT(maybeFixupBlock->numSuccessors() == 1,
|
||||
"OSR fixup block should have exactly one successor");
|
||||
MOZ_ASSERT(pred != graph_.entryBlock(),
|
||||
MOZ_ASSERT(maybeFixupBlock != graph_.entryBlock(),
|
||||
"OSR fixup block shouldn't be the entry block");
|
||||
MOZ_ASSERT(pred != graph_.osrBlock(),
|
||||
MOZ_ASSERT(maybeFixupBlock != graph_.osrBlock(),
|
||||
"OSR fixup block shouldn't be the OSR entry block");
|
||||
pred->mark();
|
||||
maybeFixupBlock->mark();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1159,6 +1198,11 @@ ValueNumberer::run(UpdateAliasAnalysisFlag updateAliasAnalysis)
|
||||
JitSpew(JitSpew_GVN, "Running GVN on graph (with %llu blocks)",
|
||||
uint64_t(graph_.numBlocks()));
|
||||
|
||||
// Adding fixup blocks only make sense iff we have a second entry point into
|
||||
// the graph which cannot be reached any more from the entry point.
|
||||
if (graph_.osrBlock())
|
||||
insertOSRFixups();
|
||||
|
||||
// Top level non-sparse iteration loop. If an iteration performs a
|
||||
// significant change, such as discarding a block which changes the
|
||||
// dominator tree and may enable more optimization, this loop takes another
|
||||
@@ -1182,7 +1226,7 @@ ValueNumberer::run(UpdateAliasAnalysisFlag updateAliasAnalysis)
|
||||
}
|
||||
|
||||
if (blocksRemoved_) {
|
||||
if (!AccountForCFGChanges(mir_, graph_, dependenciesBroken_))
|
||||
if (!AccountForCFGChanges(mir_, graph_, dependenciesBroken_, /* underValueNumberer = */ true))
|
||||
return false;
|
||||
|
||||
blocksRemoved_ = false;
|
||||
|
||||
@@ -101,6 +101,8 @@ class ValueNumberer
|
||||
bool visitBlock(MBasicBlock* block, const MBasicBlock* root);
|
||||
bool visitDominatorTree(MBasicBlock* root);
|
||||
bool visitGraph();
|
||||
|
||||
bool insertOSRFixups();
|
||||
bool cleanupOSRFixups();
|
||||
|
||||
public:
|
||||
|
||||
@@ -13,24 +13,24 @@ BEGIN_TEST(testForceLexicalInitialization)
|
||||
{
|
||||
// Attach an uninitialized lexical to a scope and ensure that it's
|
||||
// set to undefined
|
||||
RootedGlobalObject g(cx, cx->global());
|
||||
Rooted<ClonedBlockObject*> scope(cx, ClonedBlockObject::createGlobal(cx, g));
|
||||
js::RootedGlobalObject g(cx, cx->global());
|
||||
JS::Rooted<js::ClonedBlockObject*> scope(cx, js::ClonedBlockObject::createGlobal(cx, g));
|
||||
|
||||
RootedValue uninitialized(cx, MagicValue(JS_UNINITIALIZED_LEXICAL));
|
||||
RootedPropertyName name(cx, Atomize(cx, "foopi", 4)->asPropertyName());
|
||||
RootedId id(cx, NameToId(name));
|
||||
JS::RootedValue uninitialized(cx, JS::MagicValue(JS_UNINITIALIZED_LEXICAL));
|
||||
js::RootedPropertyName name(cx, Atomize(cx, "foopi", 4)->asPropertyName());
|
||||
JS::RootedId id(cx, NameToId(name));
|
||||
unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT;
|
||||
|
||||
NativeDefineProperty(cx, scope, id, uninitialized, nullptr, nullptr, attrs);
|
||||
|
||||
// Verify that "foopi" is uninitialized
|
||||
const Value v = scope->getSlot(scope->lookup(cx, id)->slot());
|
||||
const JS::Value v = scope->getSlot(scope->lookup(cx, id)->slot());
|
||||
CHECK(v.isMagic(JS_UNINITIALIZED_LEXICAL));
|
||||
|
||||
ForceLexicalInitialization(cx, scope);
|
||||
|
||||
// Verify that "foopi" has been initialized to undefined
|
||||
const Value v2 = scope->getSlot(scope->lookup(cx, id)->slot());
|
||||
const JS::Value v2 = scope->getSlot(scope->lookup(cx, id)->slot());
|
||||
CHECK(v2.isUndefined());
|
||||
|
||||
return true;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "jsapi-tests/tests.h"
|
||||
|
||||
static bool WriteValidBytes(wasm::Encoder& encoder, bool* passed)
|
||||
static bool WriteValidBytes(js::wasm::Encoder& encoder, bool* passed)
|
||||
{
|
||||
*passed = false;
|
||||
if (!encoder.empty())
|
||||
@@ -40,6 +40,7 @@ static bool WriteValidBytes(wasm::Encoder& encoder, bool* passed)
|
||||
|
||||
BEGIN_TEST(testWasmLEB128_encoding)
|
||||
{
|
||||
using namespace js;
|
||||
using namespace wasm;
|
||||
|
||||
Bytes bytes;
|
||||
@@ -69,6 +70,7 @@ END_TEST(testWasmLEB128_encoding)
|
||||
|
||||
BEGIN_TEST(testWasmLEB128_valid_decoding)
|
||||
{
|
||||
using namespace js;
|
||||
using namespace wasm;
|
||||
|
||||
Bytes bytes;
|
||||
@@ -119,6 +121,7 @@ END_TEST(testWasmLEB128_valid_decoding)
|
||||
|
||||
BEGIN_TEST(testWasmLEB128_invalid_decoding)
|
||||
{
|
||||
using namespace js;
|
||||
using namespace wasm;
|
||||
|
||||
Bytes bytes;
|
||||
|
||||
@@ -139,7 +139,7 @@ BEGIN_TEST(testXDR_sourceMap)
|
||||
CHECK(script);
|
||||
|
||||
size_t len = strlen(*sm);
|
||||
UniqueTwoByteChars expected_wrapper(js::InflateString(cx, *sm, &len));
|
||||
JS::UniqueTwoByteChars expected_wrapper(js::InflateString(cx, *sm, &len));
|
||||
char16_t *expected = expected_wrapper.get();
|
||||
CHECK(expected);
|
||||
|
||||
|
||||
+21
-7
@@ -254,6 +254,7 @@ class Bindings
|
||||
}
|
||||
|
||||
public:
|
||||
static const uint32_t BODY_LEVEL_LEXICAL_LIMIT = UINT16_LIMIT;
|
||||
|
||||
static const uint32_t BLOCK_SCOPED_LIMIT = UINT16_LIMIT;
|
||||
|
||||
@@ -362,7 +363,6 @@ class Bindings
|
||||
static_assert(sizeof(Bindings) % js::gc::CellSize == 0,
|
||||
"Size of Bindings must be an integral multiple of js::gc::CellSize");
|
||||
|
||||
|
||||
template <class Outer>
|
||||
class BindingsOperations
|
||||
{
|
||||
@@ -437,12 +437,26 @@ class MutableBindingsOperations : public BindingsOperations<Outer>
|
||||
void setBindingArray(const Binding* bindingArray, uintptr_t temporaryBit) {
|
||||
bindings().bindingArrayAndFlag_ = uintptr_t(bindingArray) | temporaryBit;
|
||||
}
|
||||
void setNumArgs(uint16_t num) { bindings().numArgs_ = num; }
|
||||
void setNumVars(uint32_t num) { bindings().numVars_ = num; }
|
||||
void setNumBodyLevelLexicals(uint16_t num) { bindings().numBodyLevelLexicals_ = num; }
|
||||
void setNumBlockScoped(uint16_t num) { bindings().numBlockScoped_ = num; }
|
||||
void setNumUnaliasedVars(uint32_t num) { bindings().numUnaliasedVars_ = num; }
|
||||
void setNumUnaliasedBodyLevelLexicals(uint16_t num) {
|
||||
void setNumArgs(uint32_t num) {
|
||||
MOZ_ASSERT(num <= UINT16_MAX);
|
||||
bindings().numArgs_ = num;
|
||||
}
|
||||
void setNumVars(uint32_t num) {
|
||||
bindings().numVars_ = num;
|
||||
}
|
||||
void setNumBodyLevelLexicals(uint32_t num) {
|
||||
MOZ_ASSERT(num <= UINT16_MAX);
|
||||
bindings().numBodyLevelLexicals_ = num;
|
||||
}
|
||||
void setNumBlockScoped(uint32_t num) {
|
||||
MOZ_ASSERT(num <= UINT16_MAX);
|
||||
bindings().numBlockScoped_ = num;
|
||||
}
|
||||
void setNumUnaliasedVars(uint32_t num) {
|
||||
bindings().numUnaliasedVars_ = num;
|
||||
}
|
||||
void setNumUnaliasedBodyLevelLexicals(uint32_t num) {
|
||||
MOZ_ASSERT(num <= UINT16_MAX);
|
||||
bindings().numUnaliasedBodyLevelLexicals_ = num;
|
||||
}
|
||||
void setAliasedBodyLevelLexicalBegin(uint32_t offset) {
|
||||
|
||||
@@ -42,6 +42,17 @@ assertThrowsInstanceOf(function () {
|
||||
`);
|
||||
}, SyntaxError);
|
||||
|
||||
// Tests that redeclaring a var inside the catch is not allowed if there's a
|
||||
// body-level lexical.
|
||||
assertThrowsInstanceOf(function () {
|
||||
eval(`
|
||||
let x;
|
||||
try {} catch (x) {
|
||||
var x;
|
||||
}
|
||||
`);
|
||||
}, SyntaxError);
|
||||
|
||||
var log = '';
|
||||
var x = 'global-x';
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ const SYNTAX_ERROR_STMTS = [
|
||||
"delete ({x=1})",
|
||||
"delete {x=1} = {}",
|
||||
"({x=1}.abc)",
|
||||
"x > (0, {a = b} );",
|
||||
// declarations
|
||||
"var x = 0 + {a=1} = {}",
|
||||
"let o = {x=1};",
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
var hits = 0;
|
||||
|
||||
var p = { toString() { hits++; return "prop" } };
|
||||
var obj = { foo: 1 };
|
||||
|
||||
|
||||
var ops = [["obj[p]++", 2],
|
||||
["++obj[p]", 2],
|
||||
["--obj[p]", 0],
|
||||
["obj[p]--", 0],
|
||||
["obj[p] += 2", 3],
|
||||
["obj[p] -= 2", -1],
|
||||
["obj[p] *= 2", 2],
|
||||
["obj[p] /= 2", 0.5],
|
||||
["obj[p] %= 2", 1],
|
||||
["obj[p] >>>= 2", 0],
|
||||
["obj[p] >>= 2", 0],
|
||||
["obj[p] <<= 2", 4],
|
||||
["obj[p] |= 2", 3],
|
||||
["obj[p] ^= 2", 3],
|
||||
["obj[p] &= 2", 0]];
|
||||
|
||||
var testHits = 0;
|
||||
for (let op of ops) {
|
||||
// Seed the value for each test.
|
||||
obj.prop = 1;
|
||||
|
||||
// Do the operation.
|
||||
eval(op[0]);
|
||||
assertEq(obj.prop, op[1]);
|
||||
|
||||
// We should always call toString once, for each operation.
|
||||
testHits++;
|
||||
assertEq(hits, testHits);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0,0,"OK");
|
||||
@@ -7,6 +7,7 @@
|
||||
#ifndef threading_ExclusiveData_h
|
||||
#define threading_ExclusiveData_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Move.h"
|
||||
|
||||
@@ -80,7 +81,7 @@ template <typename T>
|
||||
class ExclusiveData
|
||||
{
|
||||
mutable Mutex lock_;
|
||||
mutable T value_;
|
||||
mutable mozilla::AlignedStorage2<T> value_;
|
||||
|
||||
ExclusiveData(const ExclusiveData&) = delete;
|
||||
ExclusiveData& operator=(const ExclusiveData&) = delete;
|
||||
@@ -94,15 +95,19 @@ class ExclusiveData
|
||||
* value.
|
||||
*/
|
||||
template <typename U>
|
||||
explicit ExclusiveData(U&& u)
|
||||
: value_(mozilla::Forward<U>(u))
|
||||
{
|
||||
explicit ExclusiveData(U&& u) {
|
||||
new (value_.addr()) T(mozilla::Forward<U>(u));
|
||||
}
|
||||
|
||||
ExclusiveData(ExclusiveData&& rhs)
|
||||
: value_(mozilla::Move(rhs.value_))
|
||||
{
|
||||
~ExclusiveData() {
|
||||
acquire();
|
||||
value_.addr()->~T();
|
||||
release();
|
||||
}
|
||||
|
||||
ExclusiveData(ExclusiveData&& rhs) {
|
||||
MOZ_ASSERT(&rhs != this, "self-move disallowed!");
|
||||
new (value_.addr()) T(mozilla::Move(*rhs.value_.addr()));
|
||||
}
|
||||
|
||||
ExclusiveData& operator=(ExclusiveData&& rhs) {
|
||||
@@ -148,7 +153,7 @@ class ExclusiveData
|
||||
|
||||
T& get() const {
|
||||
MOZ_ASSERT(parent_);
|
||||
return parent_->value_;
|
||||
return *parent_->value_.addr();
|
||||
}
|
||||
|
||||
operator T& () const { return get(); }
|
||||
|
||||
@@ -119,7 +119,7 @@ class DateTimeInfo
|
||||
}
|
||||
};
|
||||
|
||||
friend bool ::JS_Init();
|
||||
friend const char* ::JS_InitWithFailureDiagnostic();
|
||||
|
||||
// Initialize global date/time tracking state. This operation occurs
|
||||
// during, and is restricted to, SpiderMonkey initialization.
|
||||
|
||||
@@ -295,7 +295,9 @@ GlobalObject::initStarGenerators(JSContext* cx, Handle<GlobalObject*> global)
|
||||
if (!iteratorProto)
|
||||
return false;
|
||||
|
||||
RootedPlainObject genObjectProto(cx, NewObjectWithGivenProto<PlainObject>(cx, iteratorProto));
|
||||
RootedObject genObjectProto(cx, global->createBlankPrototypeInheriting(cx,
|
||||
&PlainObject::class_,
|
||||
iteratorProto));
|
||||
if (!genObjectProto)
|
||||
return false;
|
||||
if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods))
|
||||
|
||||
@@ -59,8 +59,8 @@ CheckMessageParameterCounts()
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_Init(void)
|
||||
JS_PUBLIC_API(const char*)
|
||||
JS_InitWithFailureDiagnostic(void)
|
||||
{
|
||||
MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
|
||||
"must call JS_Init once before any JSAPI operation except "
|
||||
@@ -76,18 +76,18 @@ JS_Init(void)
|
||||
|
||||
using js::TlsPerThreadData;
|
||||
if (!TlsPerThreadData.init())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: TlsPerThreadData.init() failed";
|
||||
|
||||
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
|
||||
if (!js::oom::InitThreadType())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: js::oom::InitThreadType() failed";
|
||||
js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
|
||||
#endif
|
||||
|
||||
js::jit::ExecutableAllocator::initStatic();
|
||||
|
||||
if (!js::jit::InitializeIon())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: js::jit::InitializeIon() failed";
|
||||
|
||||
js::DateTimeInfo::init();
|
||||
|
||||
@@ -95,20 +95,27 @@ JS_Init(void)
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
u_init(&err);
|
||||
if (U_FAILURE(err))
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: u_init() failed";
|
||||
#endif // EXPOSE_INTL_API
|
||||
|
||||
if (!js::CreateHelperThreadsState())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: js::CreateHelperThreadState() failed";
|
||||
|
||||
if (!FutexRuntime::initialize())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: FutexRuntime::initialize() failed";
|
||||
|
||||
if (!js::gcstats::Statistics::initialize())
|
||||
return false;
|
||||
return "JS_InitWithFailureDiagnostic: js::gcstats::Statistics::initialize() failed";
|
||||
|
||||
libraryInitState = InitState::Running;
|
||||
return true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(bool)
|
||||
JS_Init(void)
|
||||
{
|
||||
const char* failure = JS_InitWithFailureDiagnostic();
|
||||
return !failure;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
||||
@@ -205,7 +205,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
||||
canUseSignalHandlers_(false),
|
||||
defaultFreeOp_(thisFromCtor()),
|
||||
debuggerMutations(0),
|
||||
securityCallbacks(const_cast<JSSecurityCallbacks*>(&NullSecurityCallbacks)),
|
||||
securityCallbacks(&NullSecurityCallbacks),
|
||||
DOMcallbacks(nullptr),
|
||||
destroyPrincipals(nullptr),
|
||||
readPrincipals(nullptr),
|
||||
@@ -698,9 +698,7 @@ JSRuntime::getDefaultLocale()
|
||||
if (defaultLocale)
|
||||
return defaultLocale;
|
||||
|
||||
char* locale;
|
||||
char* lang;
|
||||
char* p;
|
||||
const char* locale;
|
||||
#ifdef HAVE_SETLOCALE
|
||||
locale = setlocale(LC_ALL, nullptr);
|
||||
#else
|
||||
@@ -708,10 +706,13 @@ JSRuntime::getDefaultLocale()
|
||||
#endif
|
||||
// convert to a well-formed BCP 47 language tag
|
||||
if (!locale || !strcmp(locale, "C"))
|
||||
locale = const_cast<char*>("und");
|
||||
lang = JS_strdup(this, locale);
|
||||
locale = "und";
|
||||
|
||||
char* lang = JS_strdup(this, locale);
|
||||
if (!lang)
|
||||
return nullptr;
|
||||
|
||||
char* p;
|
||||
if ((p = strchr(lang, '.')))
|
||||
*p = '\0';
|
||||
while ((p = strchr(lang, '_')))
|
||||
|
||||
@@ -895,7 +895,7 @@ IsSavedFrame(JSObject* obj)
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
JSObject* unwrapped = CheckedUnwrap(obj);
|
||||
JSObject* unwrapped = js::CheckedUnwrap(obj);
|
||||
if (!unwrapped)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -141,8 +141,10 @@ class StaticBlockScope : public NestedStaticScope
|
||||
|
||||
/* Return the number of variables associated with this block. */
|
||||
uint32_t numVariables() const {
|
||||
// TODO: propertyCount() is O(n), use O(1) lastProperty()->slot() instead
|
||||
return propertyCount();
|
||||
uint32_t num = 0;
|
||||
if (!lastProperty()->isEmptyShape())
|
||||
num = lastProperty()->slot() + 1 - RESERVED_SLOTS;
|
||||
return num;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "gc/Barrier.h"
|
||||
#include "gc/Zone.h"
|
||||
|
||||
#include "vm/Runtime-inl.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/* static */ void
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "jscompartment.h"
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace JS {
|
||||
|
||||
@@ -698,6 +698,7 @@ UnboxedPlainObject::createWithProperties(ExclusiveContext* cx, HandleObjectGroup
|
||||
|
||||
#ifndef JS_CODEGEN_NONE
|
||||
if (cx->isJSContext() &&
|
||||
!group->unknownProperties() &&
|
||||
!layout.constructorCode() &&
|
||||
cx->asJSContext()->runtime()->jitSupportsFloatingPoint)
|
||||
{
|
||||
|
||||
@@ -570,7 +570,7 @@ static bool
|
||||
HasBoxAncestor(nsIFrame* aFrame)
|
||||
{
|
||||
for (nsIFrame* f = aFrame; f; f = f->GetParent()) {
|
||||
if (f->IsBoxFrame()) {
|
||||
if (f->IsXULBoxFrame()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1117,6 +1117,8 @@ RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
|
||||
{
|
||||
nsAnimationManager* animationManager =
|
||||
mRestyleManager->PresContext()->AnimationManager();
|
||||
nsTransitionManager* transitionManager =
|
||||
mRestyleManager->PresContext()->TransitionManager();
|
||||
for (nsIContent* content : aArray) {
|
||||
if (content->GetPrimaryFrame()) {
|
||||
continue;
|
||||
@@ -1124,6 +1126,7 @@ RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
|
||||
dom::Element* element = content->AsElement();
|
||||
|
||||
animationManager->StopAnimationsForElement(element, aPseudoType);
|
||||
transitionManager->StopTransitionsForElement(element, aPseudoType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,8 +250,8 @@ public:
|
||||
nsStyleContext* aOldStyleContext,
|
||||
RefPtr<nsStyleContext>* aNewStyleContext /* inout */);
|
||||
|
||||
// AnimationsWithDestroyedFrame is used to stop animations on elements that
|
||||
// have no frame at the end of the restyling process.
|
||||
// AnimationsWithDestroyedFrame is used to stop animations and transitions
|
||||
// on elements that have no frame at the end of the restyling process.
|
||||
// It only lives during the restyling process.
|
||||
class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
|
||||
public:
|
||||
@@ -260,13 +260,10 @@ public:
|
||||
// object. (This is generally easy since the caller is typically a
|
||||
// method of RestyleManager.)
|
||||
explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
|
||||
~AnimationsWithDestroyedFrame()
|
||||
{
|
||||
}
|
||||
|
||||
// This method takes the content node for the generated content for
|
||||
// animation on ::before and ::after, rather than the content node for
|
||||
// the real element.
|
||||
// animation/transition on ::before and ::after, rather than the
|
||||
// content node for the real element.
|
||||
void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
|
||||
MOZ_ASSERT(aContent);
|
||||
CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
|
||||
@@ -291,7 +288,7 @@ public:
|
||||
AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
|
||||
|
||||
// Below three arrays might include elements that have already had their
|
||||
// animations stopped.
|
||||
// animations or transitions stopped.
|
||||
//
|
||||
// mBeforeContents and mAfterContents hold the real element rather than
|
||||
// the content node for the generated content (which might change during
|
||||
|
||||
@@ -123,8 +123,8 @@ RestyleTracker::DoProcessRestyles()
|
||||
bool isTimelineRecording = timelines && timelines->HasConsumer(docShell);
|
||||
|
||||
// Create a AnimationsWithDestroyedFrame during restyling process to
|
||||
// stop animations on elements that have no frame at the end of the
|
||||
// restyling process.
|
||||
// stop animations and transitions on elements that have no frame at the end
|
||||
// of the restyling process.
|
||||
RestyleManager::AnimationsWithDestroyedFrame
|
||||
animationsWithDestroyedFrame(mRestyleManager);
|
||||
|
||||
|
||||
@@ -425,7 +425,7 @@ static bool
|
||||
ShouldSuppressFloatingOfDescendants(nsIFrame* aFrame)
|
||||
{
|
||||
return aFrame->IsFrameOfType(nsIFrame::eMathML) ||
|
||||
aFrame->IsBoxFrame() ||
|
||||
aFrame->IsXULBoxFrame() ||
|
||||
::IsFlexOrGridContainer(aFrame);
|
||||
}
|
||||
|
||||
@@ -8345,7 +8345,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
||||
// (If we're in the XUL block-wrapping situation, parentFrame is the
|
||||
// wrapper frame.)
|
||||
nsIFrame* grandparentFrame = parentFrame->GetParent();
|
||||
if (grandparentFrame && grandparentFrame->IsBoxFrame() &&
|
||||
if (grandparentFrame && grandparentFrame->IsXULBoxFrame() &&
|
||||
(grandparentFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
|
||||
// check if this frame is the only one needing wrapping
|
||||
aChild == AnyKidsNeedBlockParent(parentFrame->PrincipalChildList().FirstChild()) &&
|
||||
@@ -10486,6 +10486,49 @@ void nsCSSFrameConstructor::CreateNeededPseudoSiblings(
|
||||
iter.InsertItem(newItem);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
FrameWantsToBeInAnonymousItem(const nsIAtom* aParentType, const nsIFrame* aFrame)
|
||||
{
|
||||
// Note: This needs to match the logic in
|
||||
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
|
||||
if (aParentType == nsGkAtoms::gridContainerFrame) {
|
||||
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
|
||||
}
|
||||
MOZ_ASSERT(aParentType == nsGkAtoms::flexContainerFrame);
|
||||
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
|
||||
aFrame->GetType() == nsGkAtoms::placeholderFrame;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
VerifyGridFlexContainerChildren(nsIFrame* aParentFrame,
|
||||
const nsFrameList& aChildren)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
auto parentType = aParentFrame->GetType();
|
||||
if (parentType != nsGkAtoms::flexContainerFrame &&
|
||||
parentType != nsGkAtoms::gridContainerFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool prevChildWasAnonItem = false;
|
||||
for (const nsIFrame* child : aChildren) {
|
||||
MOZ_ASSERT(!FrameWantsToBeInAnonymousItem(parentType, child),
|
||||
"frame wants to be inside an anonymous item, but it isn't");
|
||||
if (IsAnonymousFlexOrGridItem(child)) {
|
||||
AssertAnonymousFlexOrGridItemParent(child, aParentFrame);
|
||||
MOZ_ASSERT(!prevChildWasAnonItem, "two anon items in a row");
|
||||
nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
|
||||
MOZ_ASSERT(firstWrappedChild, "anonymous item shouldn't be empty");
|
||||
prevChildWasAnonItem = true;
|
||||
} else {
|
||||
prevChildWasAnonItem = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void
|
||||
nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aState,
|
||||
FrameConstructionItemList& aItems,
|
||||
@@ -10504,6 +10547,7 @@ nsCSSFrameConstructor::ConstructFramesFromItemList(nsFrameConstructorState& aSta
|
||||
ConstructFramesFromItem(aState, iter, aParentFrame, aFrameItems);
|
||||
}
|
||||
|
||||
VerifyGridFlexContainerChildren(aParentFrame, aFrameItems);
|
||||
NS_ASSERTION(!aState.mHavePendingPopupgroup,
|
||||
"Should have proccessed it by now");
|
||||
}
|
||||
@@ -10703,7 +10747,7 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
||||
|
||||
ConstructFramesFromItemList(aState, itemsToConstruct, aFrame, aFrameItems);
|
||||
|
||||
NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsBoxFrame(),
|
||||
NS_ASSERTION(!aAllowBlockStyles || !aFrame->IsXULBoxFrame(),
|
||||
"can't be both block and box");
|
||||
|
||||
if (haveFirstLetterStyle) {
|
||||
@@ -10716,15 +10760,15 @@ nsCSSFrameConstructor::ProcessChildren(nsFrameConstructorState& aState,
|
||||
|
||||
// We might end up with first-line frames that change
|
||||
// AnyKidsNeedBlockParent() without changing itemsToConstruct, but that
|
||||
// should never happen for cases whan aFrame->IsBoxFrame().
|
||||
NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsBoxFrame(),
|
||||
// should never happen for cases whan aFrame->IsXULBoxFrame().
|
||||
NS_ASSERTION(!haveFirstLineStyle || !aFrame->IsXULBoxFrame(),
|
||||
"Shouldn't have first-line style if we're a box");
|
||||
NS_ASSERTION(!aFrame->IsBoxFrame() ||
|
||||
NS_ASSERTION(!aFrame->IsXULBoxFrame() ||
|
||||
itemsToConstruct.AnyItemsNeedBlockParent() ==
|
||||
(AnyKidsNeedBlockParent(aFrameItems.FirstChild()) != nullptr),
|
||||
"Something went awry in our block parent calculations");
|
||||
|
||||
if (aFrame->IsBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
|
||||
if (aFrame->IsXULBoxFrame() && itemsToConstruct.AnyItemsNeedBlockParent()) {
|
||||
// XXXbz we could do this on the FrameConstructionItemList level,
|
||||
// no? And if we cared we could look through the item list
|
||||
// instead of groveling through the framelist here..
|
||||
@@ -12061,7 +12105,7 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
||||
|
||||
// Situation #1 is a XUL frame that contains frames that are required
|
||||
// to be wrapped in blocks.
|
||||
if (aFrame->IsBoxFrame() &&
|
||||
if (aFrame->IsXULBoxFrame() &&
|
||||
!(aFrame->GetStateBits() & NS_STATE_BOX_WRAPS_KIDS_IN_BLOCK) &&
|
||||
aItems.AnyItemsNeedBlockParent()) {
|
||||
RecreateFramesForContent(aFrame->GetContent(), true,
|
||||
|
||||
@@ -5519,21 +5519,6 @@ nsImageRenderer::IsAnimatedImage()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
nsImageRenderer::IsContainerAvailable(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
if (mType != eStyleImageType_Image || !mImageContainer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
return mImageContainer->IsImageContainerAvailable(aManager, flags);
|
||||
}
|
||||
|
||||
already_AddRefed<imgIContainer>
|
||||
nsImageRenderer::GetImage()
|
||||
{
|
||||
|
||||
@@ -252,16 +252,6 @@ public:
|
||||
bool IsRasterImage();
|
||||
bool IsAnimatedImage();
|
||||
|
||||
/**
|
||||
* @return true if this nsImageRenderer wraps an image which has an
|
||||
* ImageContainer available.
|
||||
*
|
||||
* If IsContainerAvailable() returns true, GetImage() will return a non-null
|
||||
* imgIContainer which callers can use to retrieve the ImageContainer.
|
||||
*/
|
||||
bool IsContainerAvailable(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder);
|
||||
|
||||
/// Retrieves the image associated with this nsImageRenderer, if there is one.
|
||||
already_AddRefed<imgIContainer> GetImage();
|
||||
|
||||
|
||||
+148
-125
@@ -1941,7 +1941,7 @@ void nsDisplayList::DeleteAll() {
|
||||
static bool
|
||||
GetMouseThrough(const nsIFrame* aFrame)
|
||||
{
|
||||
if (!aFrame->IsBoxFrame())
|
||||
if (!aFrame->IsXULBoxFrame())
|
||||
return false;
|
||||
|
||||
const nsIFrame* frame = aFrame;
|
||||
@@ -1951,7 +1951,7 @@ GetMouseThrough(const nsIFrame* aFrame)
|
||||
} else if (frame->GetStateBits() & NS_FRAME_MOUSE_THROUGH_NEVER) {
|
||||
return false;
|
||||
}
|
||||
frame = nsBox::GetParentBox(frame);
|
||||
frame = nsBox::GetParentXULBox(frame);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -2348,32 +2348,33 @@ nsDisplayBackgroundImage::nsDisplayBackgroundImage(nsDisplayListBuilder* aBuilde
|
||||
: nsDisplayImageContainer(aBuilder, aFrame)
|
||||
, mBackgroundStyle(aBackgroundStyle)
|
||||
, mLayer(aLayer)
|
||||
, mIsRasterImage(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayBackgroundImage);
|
||||
|
||||
mBounds = GetBoundsInternal(aBuilder);
|
||||
mDestArea = GetDestAreaInternal(aBuilder);
|
||||
if (ShouldFixToViewport(aBuilder)) {
|
||||
mAnimatedGeometryRoot = aBuilder->FindAnimatedGeometryRootFor(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsDisplayBackgroundImage::GetDestAreaInternal(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
if (!mBackgroundStyle) {
|
||||
return nsRect();
|
||||
}
|
||||
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
const nsStyleImageLayers::Layer& layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
||||
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
||||
|
||||
nsBackgroundLayerState state =
|
||||
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
|
||||
borderArea, borderArea, layer);
|
||||
return state.mDestArea;
|
||||
|
||||
mFillRect = state.mFillArea;
|
||||
mDestRect = state.mDestArea;
|
||||
|
||||
nsImageRenderer* imageRenderer = &state.mImageRenderer;
|
||||
// We only care about images here, not gradients.
|
||||
if (imageRenderer->IsRasterImage()) {
|
||||
mIsRasterImage = true;
|
||||
mImage = imageRenderer->GetImage();
|
||||
}
|
||||
}
|
||||
|
||||
nsDisplayBackgroundImage::~nsDisplayBackgroundImage()
|
||||
@@ -2606,24 +2607,16 @@ nsDisplayBackgroundImage::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuil
|
||||
if (mBackgroundStyle->mImage.mLayers.Length() != 1)
|
||||
return false;
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
||||
|
||||
if (layer.mAttachment != NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED)
|
||||
return false;
|
||||
|
||||
nsBackgroundLayerState state =
|
||||
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
|
||||
borderArea, aClipRect, layer);
|
||||
nsImageRenderer* imageRenderer = &state.mImageRenderer;
|
||||
// We only care about images here, not gradients.
|
||||
if (!imageRenderer->IsRasterImage())
|
||||
if (!mIsRasterImage)
|
||||
return false;
|
||||
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
*aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
|
||||
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
*aDestRect = nsLayoutUtils::RectToGfxRect(mFillRect, appUnitsPerDevPixel);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -2658,75 +2651,35 @@ nsDisplayBackgroundImage::CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
uint32_t flags = aBuilder->GetBackgroundPaintFlags();
|
||||
nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
|
||||
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
||||
|
||||
nsBackgroundLayerState state =
|
||||
nsCSSRendering::PrepareImageLayer(presContext, mFrame, flags,
|
||||
borderArea, borderArea, layer);
|
||||
nsImageRenderer* imageRenderer = &state.mImageRenderer;
|
||||
// We only care about images here, not gradients.
|
||||
if (!imageRenderer->IsRasterImage()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!imageRenderer->IsContainerAvailable(aManager, aBuilder)) {
|
||||
// The image is not ready to be made into a layer yet.
|
||||
return false;
|
||||
}
|
||||
|
||||
// We currently can't handle tiled backgrounds.
|
||||
if (!state.mDestArea.Contains(state.mFillArea)) {
|
||||
if (!mDestRect.Contains(mFillRect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For 'contain' and 'cover', we allow any pixel of the image to be sampled
|
||||
// because there isn't going to be any spriting/atlasing going on.
|
||||
const nsStyleImageLayers::Layer &layer = mBackgroundStyle->mImage.mLayers[mLayer];
|
||||
bool allowPartialImages =
|
||||
(layer.mSize.mWidthType == nsStyleImageLayers::Size::eContain ||
|
||||
layer.mSize.mWidthType == nsStyleImageLayers::Size::eCover);
|
||||
if (!allowPartialImages && !state.mFillArea.Contains(state.mDestArea)) {
|
||||
if (!allowPartialImages && !mFillRect.Contains(mDestRect)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX Ignoring state.mAnchor. ImageLayer drawing snaps mDestArea edges to
|
||||
// layer pixel boundaries. This should be OK for now.
|
||||
|
||||
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
mImageLayerDestRect =
|
||||
LayoutDeviceRect::FromAppUnits(state.mDestArea, appUnitsPerDevPixel);
|
||||
|
||||
// Ok, we can turn this into a layer if needed.
|
||||
mImage = imageRenderer->GetImage();
|
||||
MOZ_ASSERT(mImage);
|
||||
|
||||
return true;
|
||||
return nsDisplayImageContainer::CanOptimizeToImageLayer(aManager, aBuilder);
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
nsDisplayBackgroundImage::GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder *aBuilder)
|
||||
nsRect
|
||||
nsDisplayBackgroundImage::GetDestRect()
|
||||
{
|
||||
if (!mImage) {
|
||||
MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true "
|
||||
"before calling GetContainer()");
|
||||
return nullptr;
|
||||
}
|
||||
return mDestRect;
|
||||
}
|
||||
|
||||
if (!mImageContainer) {
|
||||
// We don't have an ImageContainer yet; get it from mImage.
|
||||
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
mImageContainer = mImage->GetImageContainer(aManager, flags);
|
||||
}
|
||||
|
||||
RefPtr<ImageContainer> container = mImageContainer;
|
||||
return container.forget();
|
||||
already_AddRefed<imgIContainer>
|
||||
nsDisplayBackgroundImage::GetImage()
|
||||
{
|
||||
nsCOMPtr<imgIContainer> image = mImage;
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
nsDisplayBackgroundImage::ImageLayerization
|
||||
@@ -2787,8 +2740,11 @@ nsDisplayBackgroundImage::GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
mImage->GetWidth(&imageWidth);
|
||||
mImage->GetHeight(&imageHeight);
|
||||
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
||||
|
||||
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
LayoutDeviceRect destRect = LayoutDeviceRect::FromAppUnits(GetDestRect(), appUnitsPerDevPixel);
|
||||
|
||||
const LayerRect destLayerRect = mImageLayerDestRect * aParameters.Scale();
|
||||
const LayerRect destLayerRect = destRect * aParameters.Scale();
|
||||
|
||||
// Calculate the scaling factor for the frame.
|
||||
const gfxSize scale = gfxSize(destLayerRect.width / imageWidth,
|
||||
@@ -2824,51 +2780,6 @@ nsDisplayBackgroundImage::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayBackgroundImage::ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
|
||||
|
||||
MOZ_ASSERT(mImage);
|
||||
int32_t imageWidth;
|
||||
int32_t imageHeight;
|
||||
mImage->GetWidth(&imageWidth);
|
||||
mImage->GetHeight(&imageHeight);
|
||||
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
||||
|
||||
if (imageWidth > 0 && imageHeight > 0) {
|
||||
// We're actually using the ImageContainer. Let our frame know that it
|
||||
// should consider itself to have painted successfully.
|
||||
nsDisplayBackgroundGeometry::UpdateDrawResult(this,
|
||||
image::DrawResult::SUCCESS);
|
||||
}
|
||||
|
||||
// XXX(seth): Right now we ignore aParameters.Scale() and
|
||||
// aParameters.Offset(), because FrameLayerBuilder already applies
|
||||
// aParameters.Scale() via the layer's post-transform, and
|
||||
// aParameters.Offset() is always zero.
|
||||
MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
|
||||
|
||||
// It's possible (for example, due to downscale-during-decode) that the
|
||||
// ImageContainer this ImageLayer is holding has a different size from the
|
||||
// intrinsic size of the image. For this reason we compute the transform using
|
||||
// the ImageContainer's size rather than the image's intrinsic size.
|
||||
// XXX(seth): In reality, since the size of the ImageContainer may change
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const LayoutDevicePoint p = mImageLayerDestRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
transform.PreScale(mImageLayerDestRect.width / containerSize.width,
|
||||
mImageLayerDestRect.height / containerSize.height);
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayBackgroundImage::HitTest(nsDisplayListBuilder* aBuilder,
|
||||
const nsRect& aRect,
|
||||
@@ -3079,7 +2990,7 @@ void nsDisplayBackgroundImage::ComputeInvalidationRegion(nsDisplayListBuilder* a
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!mDestArea.IsEqualInterior(geometry->mDestArea)) {
|
||||
if (!mDestRect.IsEqualInterior(geometry->mDestRect)) {
|
||||
// Dest area changed in a way that could cause everything to change,
|
||||
// so invalidate everything (both old and new painting areas).
|
||||
aInvalidRegion->Or(bounds, geometry->mBounds);
|
||||
@@ -3305,6 +3216,118 @@ nsDisplayThemedBackground::GetBoundsInternal() {
|
||||
return r + ToReferenceFrame();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayImageContainer::ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
|
||||
|
||||
nsCOMPtr<imgIContainer> image = GetImage();
|
||||
MOZ_ASSERT(image);
|
||||
int32_t imageWidth;
|
||||
int32_t imageHeight;
|
||||
image->GetWidth(&imageWidth);
|
||||
image->GetHeight(&imageHeight);
|
||||
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
||||
|
||||
if (imageWidth > 0 && imageHeight > 0) {
|
||||
// We're actually using the ImageContainer. Let our frame know that it
|
||||
// should consider itself to have painted successfully.
|
||||
nsDisplayBackgroundGeometry::UpdateDrawResult(this,
|
||||
image::DrawResult::SUCCESS);
|
||||
}
|
||||
|
||||
// XXX(seth): Right now we ignore aParameters.Scale() and
|
||||
// aParameters.Offset(), because FrameLayerBuilder already applies
|
||||
// aParameters.Scale() via the layer's post-transform, and
|
||||
// aParameters.Offset() is always zero.
|
||||
MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
|
||||
|
||||
// It's possible (for example, due to downscale-during-decode) that the
|
||||
// ImageContainer this ImageLayer is holding has a different size from the
|
||||
// intrinsic size of the image. For this reason we compute the transform using
|
||||
// the ImageContainer's size rather than the image's intrinsic size.
|
||||
// XXX(seth): In reality, since the size of the ImageContainer may change
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
const LayoutDeviceRect destRect =
|
||||
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
||||
|
||||
const LayoutDevicePoint p = destRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
transform.PreScale(destRect.width / containerSize.width,
|
||||
destRect.height / containerSize.height);
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
nsDisplayImageContainer::GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder *aBuilder)
|
||||
{
|
||||
nsCOMPtr<imgIContainer> image = GetImage();
|
||||
if (!image) {
|
||||
MOZ_ASSERT_UNREACHABLE("Must call CanOptimizeToImage() and get true "
|
||||
"before calling GetContainer()");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
return image->GetImageContainer(aManager, flags);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayImageContainer::CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
nsCOMPtr<imgIContainer> image = GetImage();
|
||||
if (!image) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!image->IsImageContainerAvailable(aManager, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t imageWidth;
|
||||
int32_t imageHeight;
|
||||
image->GetWidth(&imageWidth);
|
||||
image->GetHeight(&imageHeight);
|
||||
|
||||
if (imageWidth == 0 || imageHeight == 0) {
|
||||
NS_ASSERTION(false, "invalid image size");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
const LayoutDeviceRect destRect =
|
||||
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
||||
|
||||
// Calculate the scaling factor for the frame.
|
||||
const gfxSize scale = gfxSize(destRect.width / imageWidth,
|
||||
destRect.height / imageHeight);
|
||||
|
||||
if (scale.width < 0.2 || scale.height < 0.2) {
|
||||
// This would look awful as long as we can't use high-quality downscaling
|
||||
// for image layers (bug 803703), so don't turn this into an image layer.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayBackgroundColor::ApplyOpacity(nsDisplayListBuilder* aBuilder,
|
||||
float aOpacity,
|
||||
|
||||
+14
-18
@@ -2330,12 +2330,16 @@ public:
|
||||
* CanOptimizeToImageLayer() first and it returned true.
|
||||
*/
|
||||
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder) = 0;
|
||||
nsDisplayListBuilder* aBuilder);
|
||||
|
||||
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder) = 0;
|
||||
virtual void ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters) = 0;
|
||||
already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder);
|
||||
void ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters);
|
||||
|
||||
virtual already_AddRefed<imgIContainer> GetImage() = 0;
|
||||
|
||||
virtual nsRect GetDestRect() = 0;
|
||||
|
||||
virtual bool SupportsOptimizingToImage() override { return true; }
|
||||
};
|
||||
@@ -2705,11 +2709,6 @@ public:
|
||||
*/
|
||||
nsRect GetPositioningArea();
|
||||
|
||||
/**
|
||||
* Return the destination area of one instance of the image.
|
||||
*/
|
||||
nsRect GetDestArea() const { return mDestArea; }
|
||||
|
||||
/**
|
||||
* Returns true if existing rendered pixels of this display item may need
|
||||
* to be redrawn if the positioning area size changes but its position does
|
||||
@@ -2730,10 +2729,8 @@ public:
|
||||
|
||||
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder) override;
|
||||
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder *aBuilder) override;
|
||||
virtual void ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
virtual already_AddRefed<imgIContainer> GetImage() override;
|
||||
virtual nsRect GetDestRect() override;
|
||||
|
||||
static nsRegion GetInsideClipRegion(nsDisplayItem* aItem, uint8_t aClip,
|
||||
const nsRect& aRect);
|
||||
@@ -2750,7 +2747,6 @@ protected:
|
||||
gfxRect* aDestRect);
|
||||
bool IsNonEmptyFixedImage() const;
|
||||
nsRect GetBoundsInternal(nsDisplayListBuilder* aBuilder);
|
||||
nsRect GetDestAreaInternal(nsDisplayListBuilder* aBuilder);
|
||||
|
||||
void PaintInternal(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx,
|
||||
const nsRect& aBounds, nsRect* aClipRect);
|
||||
@@ -2769,12 +2765,12 @@ protected:
|
||||
// mIsThemed is true or if FindBackground returned false.
|
||||
const nsStyleBackground* mBackgroundStyle;
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
RefPtr<ImageContainer> mImageContainer;
|
||||
LayoutDeviceRect mImageLayerDestRect;
|
||||
nsRect mFillRect;
|
||||
nsRect mDestRect;
|
||||
/* Bounds of this display item */
|
||||
nsRect mBounds;
|
||||
nsRect mDestArea;
|
||||
uint32_t mLayer;
|
||||
bool mIsRasterImage;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayBackgroundImag
|
||||
: nsDisplayItemGeometry(aItem, aBuilder)
|
||||
, nsImageGeometryMixin(aItem, aBuilder)
|
||||
, mPositioningArea(aItem->GetPositioningArea())
|
||||
, mDestArea(aItem->GetDestArea())
|
||||
, mDestRect(aItem->GetDestRect())
|
||||
{}
|
||||
|
||||
void
|
||||
@@ -71,7 +71,7 @@ nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset)
|
||||
{
|
||||
nsDisplayItemGeometry::MoveBy(aOffset);
|
||||
mPositioningArea.MoveBy(aOffset);
|
||||
mDestArea.MoveBy(aOffset);
|
||||
mDestRect.MoveBy(aOffset);
|
||||
}
|
||||
|
||||
nsDisplayThemedBackgroundGeometry::nsDisplayThemedBackgroundGeometry(nsDisplayThemedBackground* aItem,
|
||||
|
||||
@@ -194,7 +194,7 @@ public:
|
||||
virtual void MoveBy(const nsPoint& aOffset) override;
|
||||
|
||||
nsRect mPositioningArea;
|
||||
nsRect mDestArea;
|
||||
nsRect mDestRect;
|
||||
};
|
||||
|
||||
class nsDisplayThemedBackgroundGeometry : public nsDisplayItemGeometry
|
||||
|
||||
@@ -477,7 +477,7 @@ nsTextControlFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
|
||||
aCBSize, aAvailableISize,
|
||||
aMargin, aBorder,
|
||||
aPadding, aShrinkWrap);
|
||||
// Disabled when there's inflation; see comment in GetPrefSize.
|
||||
// Disabled when there's inflation; see comment in GetXULPrefSize.
|
||||
MOZ_ASSERT(inflation != 1.0f ||
|
||||
ancestorAutoSize.ISize(aWM) == autoSize.ISize(aWM),
|
||||
"Incorrect size computed by ComputeAutoSize?");
|
||||
@@ -586,14 +586,14 @@ nsTextControlFrame::ReflowTextControlChild(nsIFrame* aKid,
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsTextControlFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
nsTextControlFrame::GetXULMinSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
// XXXbz why? Why not the nsBoxFrame sizes?
|
||||
return nsBox::GetMinSize(aState);
|
||||
return nsBox::GetXULMinSize(aState);
|
||||
}
|
||||
|
||||
bool
|
||||
nsTextControlFrame::IsCollapsed()
|
||||
nsTextControlFrame::IsXULCollapsed()
|
||||
{
|
||||
// We're never collapsed in the box sense.
|
||||
return false;
|
||||
|
||||
@@ -62,8 +62,8 @@ public:
|
||||
const nsHTMLReflowState& aReflowState,
|
||||
nsReflowStatus& aStatus) override;
|
||||
|
||||
virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual bool IsCollapsed() override;
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual bool IsXULCollapsed() override;
|
||||
|
||||
virtual bool IsLeaf() const override;
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div style="width: 1px;"><fieldset style="display: grid;">y<legend></legend>x</fieldset></div>
|
||||
<div style="width: 1px;"><fieldset style="display: grid; overflow:hidden">y<legend></legend>x</fieldset></div>
|
||||
<div style="width: 1px;"><fieldset style="display: flex;">y<legend></legend>x</fieldset></div>
|
||||
<div style="width: 1px;"><fieldset style="display: flex; overflow:hidden">y<legend></legend>x</fieldset></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -611,3 +611,4 @@ load details-display-none-summary-3.html
|
||||
load 1304441.html
|
||||
pref(dom.details_element.enabled,true) load summary-position-out-of-flow.html
|
||||
asserts(4) load 1225005.html # bug 682647 and bug 448083
|
||||
load 1233191.html
|
||||
|
||||
@@ -704,8 +704,8 @@ nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nsBoxLayoutState aState(aPresContext, aRC);
|
||||
nsSize minSize = rootFrame->GetMinSize(aState);
|
||||
nsSize maxSize = rootFrame->GetMaxSize(aState);
|
||||
nsSize minSize = rootFrame->GetXULMinSize(aState);
|
||||
nsSize maxSize = rootFrame->GetXULMaxSize(aState);
|
||||
|
||||
SetSizeConstraints(aPresContext, windowWidget, minSize, maxSize);
|
||||
#endif
|
||||
|
||||
@@ -2032,54 +2032,6 @@ nsFlexContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// helper for the debugging method below
|
||||
bool
|
||||
FrameWantsToBeInAnonymousFlexItem(nsIFrame* aFrame)
|
||||
{
|
||||
// Note: This needs to match the logic in
|
||||
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
|
||||
return (aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
|
||||
nsGkAtoms::placeholderFrame == aFrame->GetType());
|
||||
}
|
||||
|
||||
// Debugging method, to let us assert that our anonymous flex items are
|
||||
// set up correctly -- in particular, we assert:
|
||||
// (1) we don't have any inline non-replaced children
|
||||
// (2) we don't have any consecutive anonymous flex items
|
||||
// (3) we don't have any empty anonymous flex items
|
||||
//
|
||||
// XXXdholbert This matches what nsCSSFrameConstructor currently does, and what
|
||||
// the spec used to say. However, the spec has now changed regarding what
|
||||
// types of content get wrapped in an anonymous flexbox item. The patch that
|
||||
// implements those changes (in nsCSSFrameConstructor) will need to change
|
||||
// this method as well.
|
||||
void
|
||||
nsFlexContainerFrame::SanityCheckAnonymousFlexItems() const
|
||||
{
|
||||
bool prevChildWasAnonFlexItem = false;
|
||||
for (nsIFrame* child : mFrames) {
|
||||
MOZ_ASSERT(!FrameWantsToBeInAnonymousFlexItem(child),
|
||||
"frame wants to be inside an anonymous flex item, "
|
||||
"but it isn't");
|
||||
if (child->StyleContext()->GetPseudo() ==
|
||||
nsCSSAnonBoxes::anonymousFlexItem) {
|
||||
MOZ_ASSERT(!prevChildWasAnonFlexItem ||
|
||||
HasAnyStateBits(NS_STATE_FLEX_CHILDREN_REORDERED),
|
||||
"two anon flex items in a row (shouldn't happen, unless our "
|
||||
"children have been reordered with the 'order' property)");
|
||||
|
||||
nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
|
||||
MOZ_ASSERT(firstWrappedChild,
|
||||
"anonymous flex item is empty (shouldn't happen)");
|
||||
prevChildWasAnonFlexItem = true;
|
||||
} else {
|
||||
prevChildWasAnonFlexItem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
void
|
||||
FlexLine::FreezeItemsEarly(bool aIsUsingFlexGrow)
|
||||
{
|
||||
@@ -3677,10 +3629,6 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
SanityCheckAnonymousFlexItems();
|
||||
#endif // DEBUG
|
||||
|
||||
// If we've never reordered our children, then we can trust that they're
|
||||
// already in DOM-order, and we only need to consider their "order" property
|
||||
// when checking them for sortedness & sorting them.
|
||||
|
||||
+45
-66
@@ -183,11 +183,11 @@ InitBoxMetrics(nsIFrame* aFrame, bool aClear)
|
||||
}
|
||||
|
||||
static bool
|
||||
IsBoxWrapped(const nsIFrame* aFrame)
|
||||
IsXULBoxWrapped(const nsIFrame* aFrame)
|
||||
{
|
||||
return aFrame->GetParent() &&
|
||||
aFrame->GetParent()->IsBoxFrame() &&
|
||||
!aFrame->IsBoxFrame();
|
||||
aFrame->GetParent()->IsXULBoxFrame() &&
|
||||
!aFrame->IsXULBoxFrame();
|
||||
}
|
||||
|
||||
// Formerly the nsIFrameDebug interface
|
||||
@@ -497,7 +497,7 @@ IsFontSizeInflationContainer(nsIFrame* aFrame,
|
||||
nsGkAtoms::optgroup,
|
||||
nsGkAtoms::select) ||
|
||||
content->IsInNativeAnonymousSubtree()))) &&
|
||||
!(aFrame->IsBoxFrame() && aFrame->GetParent()->IsBoxFrame());
|
||||
!(aFrame->IsXULBoxFrame() && aFrame->GetParent()->IsXULBoxFrame());
|
||||
NS_ASSERTION(!aFrame->IsFrameOfType(nsIFrame::eLineParticipant) ||
|
||||
isInline ||
|
||||
// br frames and mathml frames report being line
|
||||
@@ -611,7 +611,7 @@ nsFrame::Init(nsIContent* aContent,
|
||||
|
||||
DidSetStyleContext(nullptr);
|
||||
|
||||
if (::IsBoxWrapped(this))
|
||||
if (::IsXULBoxWrapped(this))
|
||||
::InitBoxMetrics(this, false);
|
||||
}
|
||||
|
||||
@@ -710,9 +710,9 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
}
|
||||
}
|
||||
|
||||
if (HasCSSAnimations()) {
|
||||
if (HasCSSAnimations() || HasCSSTransitions()) {
|
||||
// If no new frame for this element is created by the end of the
|
||||
// restyling process, stop animations for this frame
|
||||
// restyling process, stop animations and transitions for this frame
|
||||
if (presContext->RestyleManager()->IsGecko()) {
|
||||
RestyleManager::AnimationsWithDestroyedFrame* adf =
|
||||
presContext->RestyleManager()->AsGecko()->GetAnimationsWithDestroyedFrame();
|
||||
@@ -4252,7 +4252,7 @@ nsFrame::MarkIntrinsicISizesDirty()
|
||||
{
|
||||
// This version is meant only for what used to be box-to-block adaptors.
|
||||
// It should not be called by other derived classes.
|
||||
if (::IsBoxWrapped(this)) {
|
||||
if (::IsXULBoxWrapped(this)) {
|
||||
nsBoxLayoutMetrics *metrics = BoxMetrics();
|
||||
|
||||
SizeNeedsRecalc(metrics->mPrefSize);
|
||||
@@ -5029,12 +5029,6 @@ nsIFrame::GetView() const
|
||||
return value;
|
||||
}
|
||||
|
||||
/* virtual */ nsView*
|
||||
nsIFrame::GetViewExternal() const
|
||||
{
|
||||
return GetView();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsIFrame::SetView(nsView* aView)
|
||||
{
|
||||
@@ -5068,11 +5062,6 @@ nsIFrame::SetView(nsView* aView)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame* nsIFrame::GetAncestorWithViewExternal() const
|
||||
{
|
||||
return GetAncestorWithView();
|
||||
}
|
||||
|
||||
// Find the first geometric parent that has a view
|
||||
nsIFrame* nsIFrame::GetAncestorWithView() const
|
||||
{
|
||||
@@ -5084,12 +5073,6 @@ nsIFrame* nsIFrame::GetAncestorWithView() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// virtual
|
||||
nsPoint nsIFrame::GetOffsetToExternal(const nsIFrame* aOther) const
|
||||
{
|
||||
return GetOffsetTo(aOther);
|
||||
}
|
||||
|
||||
nsPoint nsIFrame::GetOffsetTo(const nsIFrame* aOther) const
|
||||
{
|
||||
NS_PRECONDITION(aOther,
|
||||
@@ -5179,23 +5162,11 @@ nsIFrame::GetOffsetToCrossDoc(const nsIFrame* aOther, const int32_t aAPD) const
|
||||
return offset;
|
||||
}
|
||||
|
||||
// virtual
|
||||
nsIntRect nsIFrame::GetScreenRectExternal() const
|
||||
{
|
||||
return GetScreenRect();
|
||||
}
|
||||
|
||||
nsIntRect nsIFrame::GetScreenRect() const
|
||||
{
|
||||
return GetScreenRectInAppUnits().ToNearestPixels(PresContext()->AppUnitsPerCSSPixel());
|
||||
}
|
||||
|
||||
// virtual
|
||||
nsRect nsIFrame::GetScreenRectInAppUnitsExternal() const
|
||||
{
|
||||
return GetScreenRectInAppUnits();
|
||||
}
|
||||
|
||||
nsRect nsIFrame::GetScreenRectInAppUnits() const
|
||||
{
|
||||
nsPresContext* presContext = PresContext();
|
||||
@@ -5920,7 +5891,7 @@ nsFrame::UpdateOverflow()
|
||||
nsOverflowAreas overflowAreas(rect, rect);
|
||||
|
||||
if (!DoesClipChildren() &&
|
||||
!(IsCollapsed() && (IsBoxFrame() || ::IsBoxWrapped(this)))) {
|
||||
!(IsXULCollapsed() && (IsXULBoxFrame() || ::IsXULBoxWrapped(this)))) {
|
||||
nsLayoutUtils::UnionChildOverflow(this, overflowAreas);
|
||||
}
|
||||
|
||||
@@ -8008,7 +7979,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas,
|
||||
|
||||
// Note that NS_STYLE_OVERFLOW_CLIP doesn't clip the frame background,
|
||||
// so we add theme background overflow here so it's not clipped.
|
||||
if (!::IsBoxWrapped(this) && IsThemed(disp)) {
|
||||
if (!::IsXULBoxWrapped(this) && IsThemed(disp)) {
|
||||
nsRect r(bounds);
|
||||
nsPresContext *presContext = PresContext();
|
||||
if (presContext->GetTheme()->
|
||||
@@ -8655,7 +8626,7 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState)
|
||||
nsRect rect = GetRect();
|
||||
|
||||
nsMargin bp(0,0,0,0);
|
||||
GetBorderAndPadding(bp);
|
||||
GetXULBorderAndPadding(bp);
|
||||
|
||||
{
|
||||
// If we're a container for font size inflation, then shrink
|
||||
@@ -8730,7 +8701,7 @@ nsFrame::GetLineIterator()
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsFrame::GetPrefSize(nsBoxLayoutState& aState)
|
||||
nsFrame::GetXULPrefSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize size(0,0);
|
||||
DISPLAY_PREF_SIZE(this, size);
|
||||
@@ -8741,12 +8712,12 @@ nsFrame::GetPrefSize(nsBoxLayoutState& aState)
|
||||
return metrics->mPrefSize;
|
||||
}
|
||||
|
||||
if (IsCollapsed())
|
||||
if (IsXULCollapsed())
|
||||
return size;
|
||||
|
||||
// get our size in CSS.
|
||||
bool widthSet, heightSet;
|
||||
bool completelyRedefined = nsIFrame::AddCSSPrefSize(this, size, widthSet, heightSet);
|
||||
bool completelyRedefined = nsIFrame::AddXULPrefSize(this, size, widthSet, heightSet);
|
||||
|
||||
// Refresh our caches with new sizes.
|
||||
if (!completelyRedefined) {
|
||||
@@ -8766,7 +8737,7 @@ nsFrame::GetPrefSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
nsFrame::GetXULMinSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize size(0,0);
|
||||
DISPLAY_MIN_SIZE(this, size);
|
||||
@@ -8777,13 +8748,13 @@ nsFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
return size;
|
||||
}
|
||||
|
||||
if (IsCollapsed())
|
||||
if (IsXULCollapsed())
|
||||
return size;
|
||||
|
||||
// get our size in CSS.
|
||||
bool widthSet, heightSet;
|
||||
bool completelyRedefined =
|
||||
nsIFrame::AddCSSMinSize(aState, this, size, widthSet, heightSet);
|
||||
nsIFrame::AddXULMinSize(aState, this, size, widthSet, heightSet);
|
||||
|
||||
// Refresh our caches with new sizes.
|
||||
if (!completelyRedefined) {
|
||||
@@ -8801,7 +8772,7 @@ nsFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsFrame::GetMaxSize(nsBoxLayoutState& aState)
|
||||
nsFrame::GetXULMaxSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
|
||||
DISPLAY_MAX_SIZE(this, size);
|
||||
@@ -8812,35 +8783,35 @@ nsFrame::GetMaxSize(nsBoxLayoutState& aState)
|
||||
return size;
|
||||
}
|
||||
|
||||
if (IsCollapsed())
|
||||
if (IsXULCollapsed())
|
||||
return size;
|
||||
|
||||
size = nsBox::GetMaxSize(aState);
|
||||
size = nsBox::GetXULMaxSize(aState);
|
||||
metrics->mMaxSize = size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFrame::GetFlex()
|
||||
nsFrame::GetXULFlex()
|
||||
{
|
||||
nsBoxLayoutMetrics *metrics = BoxMetrics();
|
||||
if (!DoesNeedRecalc(metrics->mFlex))
|
||||
return metrics->mFlex;
|
||||
|
||||
metrics->mFlex = nsBox::GetFlex();
|
||||
metrics->mFlex = nsBox::GetXULFlex();
|
||||
|
||||
return metrics->mFlex;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
|
||||
nsFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsBoxLayoutMetrics *metrics = BoxMetrics();
|
||||
if (!DoesNeedRecalc(metrics->mAscent))
|
||||
return metrics->mAscent;
|
||||
|
||||
if (IsCollapsed()) {
|
||||
if (IsXULCollapsed()) {
|
||||
metrics->mAscent = 0;
|
||||
} else {
|
||||
// Refresh our caches with new sizes.
|
||||
@@ -8852,7 +8823,7 @@ nsFrame::GetBoxAscent(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
nsFrame::DoXULLayout(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsRect ourRect(mRect);
|
||||
|
||||
@@ -8869,7 +8840,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
BoxReflow(aState, presContext, desiredSize, rendContext,
|
||||
ourRect.x, ourRect.y, ourRect.width, ourRect.height);
|
||||
|
||||
if (IsCollapsed()) {
|
||||
if (IsXULCollapsed()) {
|
||||
SetSize(nsSize(0, 0));
|
||||
} else {
|
||||
|
||||
@@ -8880,7 +8851,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
desiredSize.BSize(outerWM) > ourSize.BSize(outerWM)) {
|
||||
|
||||
#ifdef DEBUG_GROW
|
||||
DumpBox(stdout);
|
||||
XULDumpBox(stdout);
|
||||
printf(" GREW from (%d,%d) -> (%d,%d)\n",
|
||||
ourSize.ISize(outerWM), ourSize.BSize(outerWM),
|
||||
desiredSize.ISize(outerWM), desiredSize.BSize(outerWM));
|
||||
@@ -8901,7 +8872,7 @@ nsFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
}
|
||||
}
|
||||
|
||||
// Should we do this if IsCollapsed() is true?
|
||||
// Should we do this if IsXULCollapsed() is true?
|
||||
LogicalSize size(GetLogicalSize(outerWM));
|
||||
desiredSize.ISize(outerWM) = size.ISize(outerWM);
|
||||
desiredSize.BSize(outerWM) = size.BSize(outerWM);
|
||||
@@ -9001,7 +8972,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
|
||||
// Construct a bogus parent reflow state so that there's a usable
|
||||
// containing block reflow state.
|
||||
nsMargin margin(0,0,0,0);
|
||||
GetMargin(margin);
|
||||
GetXULMargin(margin);
|
||||
|
||||
nsSize parentSize(aWidth, aHeight);
|
||||
if (parentSize.height != NS_INTRINSICSIZE)
|
||||
@@ -9026,8 +8997,8 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
|
||||
parentReflowState.SetComputedHeight(std::max(parentSize.height, 0));
|
||||
parentReflowState.ComputedPhysicalMargin().SizeTo(0, 0, 0, 0);
|
||||
// XXX use box methods
|
||||
parentFrame->GetPadding(parentReflowState.ComputedPhysicalPadding());
|
||||
parentFrame->GetBorder(parentReflowState.ComputedPhysicalBorderPadding());
|
||||
parentFrame->GetXULPadding(parentReflowState.ComputedPhysicalPadding());
|
||||
parentFrame->GetXULBorder(parentReflowState.ComputedPhysicalBorderPadding());
|
||||
parentReflowState.ComputedPhysicalBorderPadding() +=
|
||||
parentReflowState.ComputedPhysicalPadding();
|
||||
|
||||
@@ -9097,7 +9068,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
|
||||
}
|
||||
}
|
||||
|
||||
// Box layout calls SetRect before Layout, whereas non-box layout
|
||||
// Box layout calls SetRect before XULLayout, whereas non-box layout
|
||||
// calls SetRect after Reflow.
|
||||
// XXX Perhaps we should be doing this by twiddling the rect back to
|
||||
// mLastSize before calling Reflow and then switching it back, but
|
||||
@@ -9136,7 +9107,7 @@ nsFrame::BoxReflow(nsBoxLayoutState& aState,
|
||||
&reflowState, aX, aY, layoutFlags | NS_FRAME_NO_MOVE_FRAME);
|
||||
|
||||
// Save the ascent. (bug 103925)
|
||||
if (IsCollapsed()) {
|
||||
if (IsXULCollapsed()) {
|
||||
metrics->mAscent = 0;
|
||||
} else {
|
||||
if (aDesiredSize.BlockStartAscent() ==
|
||||
@@ -9245,12 +9216,12 @@ nsIFrame::SetParent(nsContainerFrame* aParent)
|
||||
{
|
||||
// Note that the current mParent may already be destroyed at this point.
|
||||
mParent = aParent;
|
||||
if (::IsBoxWrapped(this)) {
|
||||
if (::IsXULBoxWrapped(this)) {
|
||||
::InitBoxMetrics(this, true);
|
||||
} else {
|
||||
// We could call Properties().Delete(BoxMetricsProperty()); here but
|
||||
// that's kind of slow and re-parenting in such a way that we were
|
||||
// IsBoxWrapped() before but not now should be very rare, so we'll just
|
||||
// IsXULBoxWrapped() before but not now should be very rare, so we'll just
|
||||
// keep this unused frame property until this frame dies instead.
|
||||
}
|
||||
|
||||
@@ -9382,6 +9353,14 @@ nsFrame::HasCSSAnimations()
|
||||
return collection && collection->mAnimations.Length() > 0;
|
||||
}
|
||||
|
||||
bool
|
||||
nsFrame::HasCSSTransitions()
|
||||
{
|
||||
auto collection =
|
||||
AnimationCollection<CSSTransition>::GetAnimationCollection(this);
|
||||
return collection && collection->mAnimations.Length() > 0;
|
||||
}
|
||||
|
||||
// Box layout debugging
|
||||
#ifdef DEBUG_REFLOW
|
||||
int32_t gIndent2 = 0;
|
||||
@@ -10303,7 +10282,7 @@ void* nsFrame::DisplayLayoutEnter(nsIFrame* aFrame)
|
||||
DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
|
||||
if (treeNode && treeNode->mDisplay) {
|
||||
DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
|
||||
printf("Layout\n");
|
||||
printf("XULLayout\n");
|
||||
}
|
||||
return treeNode;
|
||||
}
|
||||
@@ -10415,7 +10394,7 @@ void nsFrame::DisplayLayoutExit(nsIFrame* aFrame,
|
||||
if (treeNode->mDisplay) {
|
||||
DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
|
||||
nsRect rect = aFrame->GetRect();
|
||||
printf("Layout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
|
||||
printf("XULLayout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
|
||||
}
|
||||
DR_state->DeleteTreeNode(*treeNode);
|
||||
}
|
||||
|
||||
@@ -408,11 +408,11 @@ public:
|
||||
virtual ContentOffsets CalcContentOffsetsFromFramePoint(nsPoint aPoint);
|
||||
|
||||
// Box layout methods
|
||||
virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nscoord GetFlex() override;
|
||||
virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nscoord GetXULFlex() override;
|
||||
virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
|
||||
// We compute and store the HTML content's overflow area. So don't
|
||||
// try to compute it in the box code.
|
||||
@@ -651,7 +651,7 @@ protected:
|
||||
// Fills aCursor with the appropriate information from ui
|
||||
static void FillCursorInformationFromStyle(const nsStyleUserInterface* ui,
|
||||
nsIFrame::Cursor& aCursor);
|
||||
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
|
||||
#ifdef DEBUG_LAYOUT
|
||||
virtual void GetBoxName(nsAutoString& aName) override;
|
||||
@@ -678,6 +678,9 @@ private:
|
||||
// Returns true if this frame has any kind of CSS animations.
|
||||
bool HasCSSAnimations();
|
||||
|
||||
// Returns true if this frame has any kind of CSS transitions.
|
||||
bool HasCSSTransitions();
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
public:
|
||||
/**
|
||||
|
||||
@@ -268,7 +268,7 @@ GetScrollbarMetrics(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize* aMin,
|
||||
"computations");
|
||||
|
||||
if (aMin) {
|
||||
*aMin = aBox->GetMinSize(aState);
|
||||
*aMin = aBox->GetXULMinSize(aState);
|
||||
nsBox::AddMargin(aBox, *aMin);
|
||||
if (aMin->width < 0) {
|
||||
aMin->width = 0;
|
||||
@@ -279,7 +279,7 @@ GetScrollbarMetrics(nsBoxLayoutState& aState, nsIFrame* aBox, nsSize* aMin,
|
||||
}
|
||||
|
||||
if (aPref) {
|
||||
*aPref = aBox->GetPrefSize(aState);
|
||||
*aPref = aBox->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(aBox, *aPref);
|
||||
if (aPref->width < 0) {
|
||||
aPref->width = 0;
|
||||
@@ -794,18 +794,18 @@ nsHTMLScrollFrame::GetPrefISize(nsRenderingContext *aRenderingContext)
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHTMLScrollFrame::GetPadding(nsMargin& aMargin)
|
||||
nsHTMLScrollFrame::GetXULPadding(nsMargin& aMargin)
|
||||
{
|
||||
// Our padding hangs out on the inside of the scrollframe, but XUL doesn't
|
||||
// reaize that. If we're stuck inside a XUL box, we need to claim no
|
||||
// padding.
|
||||
// @see also nsXULScrollFrame::GetPadding.
|
||||
// @see also nsXULScrollFrame::GetXULPadding.
|
||||
aMargin.SizeTo(0,0,0,0);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsHTMLScrollFrame::IsCollapsed()
|
||||
nsHTMLScrollFrame::IsXULCollapsed()
|
||||
{
|
||||
// We're never collapsed in the box sense.
|
||||
return false;
|
||||
@@ -1009,7 +1009,7 @@ nsXULScrollFrame::nsXULScrollFrame(nsStyleContext* aContext,
|
||||
: nsBoxFrame(aContext, aIsRoot),
|
||||
mHelper(ALLOW_THIS_IN_INITIALIZER_LIST(this), aIsRoot)
|
||||
{
|
||||
SetLayoutManager(nullptr);
|
||||
SetXULLayoutManager(nullptr);
|
||||
mHelper.mClipAllDescendants = aClipAllDescendants;
|
||||
}
|
||||
|
||||
@@ -1039,7 +1039,7 @@ ScrollFrameHelper::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
|
||||
nsMargin result(0, 0, 0, 0);
|
||||
|
||||
if (mVScrollbarBox) {
|
||||
nsSize size = mVScrollbarBox->GetPrefSize(*aState);
|
||||
nsSize size = mVScrollbarBox->GetXULPrefSize(*aState);
|
||||
nsBox::AddMargin(mVScrollbarBox, size);
|
||||
if (IsScrollbarOnRight())
|
||||
result.left = size.width;
|
||||
@@ -1048,7 +1048,7 @@ ScrollFrameHelper::GetDesiredScrollbarSizes(nsBoxLayoutState* aState)
|
||||
}
|
||||
|
||||
if (mHScrollbarBox) {
|
||||
nsSize size = mHScrollbarBox->GetPrefSize(*aState);
|
||||
nsSize size = mHScrollbarBox->GetXULPrefSize(*aState);
|
||||
nsBox::AddMargin(mHScrollbarBox, size);
|
||||
// We don't currently support any scripts that would require a scrollbar
|
||||
// at the top. (Are there any?)
|
||||
@@ -1207,7 +1207,7 @@ void
|
||||
ScrollFrameHelper::ScrollByLine(nsScrollbarFrame* aScrollbar, int32_t aDirection,
|
||||
nsIScrollbarMediator::ScrollSnapMode aSnap)
|
||||
{
|
||||
bool isHorizontal = aScrollbar->IsHorizontal();
|
||||
bool isHorizontal = aScrollbar->IsXULHorizontal();
|
||||
nsIntPoint delta;
|
||||
if (isHorizontal) {
|
||||
const double kScrollMultiplier =
|
||||
@@ -1253,7 +1253,7 @@ ScrollFrameHelper::ThumbMoved(nsScrollbarFrame* aScrollbar,
|
||||
nscoord aNewPos)
|
||||
{
|
||||
MOZ_ASSERT(aScrollbar != nullptr);
|
||||
bool isHorizontal = aScrollbar->IsHorizontal();
|
||||
bool isHorizontal = aScrollbar->IsXULHorizontal();
|
||||
nsPoint current = GetScrollPosition();
|
||||
nsPoint dest = current;
|
||||
if (isHorizontal) {
|
||||
@@ -1293,7 +1293,7 @@ ScrollFrameHelper::ScrollByUnit(nsScrollbarFrame* aScrollbar,
|
||||
nsIScrollbarMediator::ScrollSnapMode aSnap)
|
||||
{
|
||||
MOZ_ASSERT(aScrollbar != nullptr);
|
||||
bool isHorizontal = aScrollbar->IsHorizontal();
|
||||
bool isHorizontal = aScrollbar->IsXULHorizontal();
|
||||
nsIntPoint delta;
|
||||
if (isHorizontal) {
|
||||
delta.x = aDirection;
|
||||
@@ -1368,7 +1368,7 @@ nsXULScrollFrame::GetSplittableType() const
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULScrollFrame::GetPadding(nsMargin& aMargin)
|
||||
nsXULScrollFrame::GetXULPadding(nsMargin& aMargin)
|
||||
{
|
||||
aMargin.SizeTo(0,0,0,0);
|
||||
return NS_OK;
|
||||
@@ -1381,29 +1381,29 @@ nsXULScrollFrame::GetType() const
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsXULScrollFrame::GetBoxAscent(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::GetXULBoxAscent(nsBoxLayoutState& aState)
|
||||
{
|
||||
if (!mHelper.mScrolledFrame)
|
||||
return 0;
|
||||
|
||||
nscoord ascent = mHelper.mScrolledFrame->GetBoxAscent(aState);
|
||||
nscoord ascent = mHelper.mScrolledFrame->GetXULBoxAscent(aState);
|
||||
nsMargin m(0,0,0,0);
|
||||
GetBorderAndPadding(m);
|
||||
GetXULBorderAndPadding(m);
|
||||
ascent += m.top;
|
||||
GetMargin(m);
|
||||
GetXULMargin(m);
|
||||
ascent += m.top;
|
||||
|
||||
return ascent;
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsXULScrollFrame::GetPrefSize(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::GetXULPrefSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
#ifdef DEBUG_LAYOUT
|
||||
PropagateDebug(aState);
|
||||
#endif
|
||||
|
||||
nsSize pref = mHelper.mScrolledFrame->GetPrefSize(aState);
|
||||
nsSize pref = mHelper.mScrolledFrame->GetXULPrefSize(aState);
|
||||
|
||||
ScrollbarStyles styles = GetScrollbarStyles();
|
||||
|
||||
@@ -1411,38 +1411,38 @@ nsXULScrollFrame::GetPrefSize(nsBoxLayoutState& aState)
|
||||
|
||||
if (mHelper.mVScrollbarBox &&
|
||||
styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetPrefSize(aState);
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(mHelper.mVScrollbarBox, vSize);
|
||||
pref.width += vSize.width;
|
||||
}
|
||||
|
||||
if (mHelper.mHScrollbarBox &&
|
||||
styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetPrefSize(aState);
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(mHelper.mHScrollbarBox, hSize);
|
||||
pref.height += hSize.height;
|
||||
}
|
||||
|
||||
AddBorderAndPadding(pref);
|
||||
bool widthSet, heightSet;
|
||||
nsIFrame::AddCSSPrefSize(this, pref, widthSet, heightSet);
|
||||
nsIFrame::AddXULPrefSize(this, pref, widthSet, heightSet);
|
||||
return pref;
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsXULScrollFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::GetXULMinSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
#ifdef DEBUG_LAYOUT
|
||||
PropagateDebug(aState);
|
||||
#endif
|
||||
|
||||
nsSize min = mHelper.mScrolledFrame->GetMinSizeForScrollArea(aState);
|
||||
nsSize min = mHelper.mScrolledFrame->GetXULMinSizeForScrollArea(aState);
|
||||
|
||||
ScrollbarStyles styles = GetScrollbarStyles();
|
||||
|
||||
if (mHelper.mVScrollbarBox &&
|
||||
styles.mVertical == NS_STYLE_OVERFLOW_SCROLL) {
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetMinSize(aState);
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetXULMinSize(aState);
|
||||
AddMargin(mHelper.mVScrollbarBox, vSize);
|
||||
min.width += vSize.width;
|
||||
if (min.height < vSize.height)
|
||||
@@ -1451,7 +1451,7 @@ nsXULScrollFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
|
||||
if (mHelper.mHScrollbarBox &&
|
||||
styles.mHorizontal == NS_STYLE_OVERFLOW_SCROLL) {
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetMinSize(aState);
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetXULMinSize(aState);
|
||||
AddMargin(mHelper.mHScrollbarBox, hSize);
|
||||
min.height += hSize.height;
|
||||
if (min.width < hSize.width)
|
||||
@@ -1460,12 +1460,12 @@ nsXULScrollFrame::GetMinSize(nsBoxLayoutState& aState)
|
||||
|
||||
AddBorderAndPadding(min);
|
||||
bool widthSet, heightSet;
|
||||
nsIFrame::AddCSSMinSize(aState, this, min, widthSet, heightSet);
|
||||
nsIFrame::AddXULMinSize(aState, this, min, widthSet, heightSet);
|
||||
return min;
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsXULScrollFrame::GetMaxSize(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::GetXULMaxSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
#ifdef DEBUG_LAYOUT
|
||||
PropagateDebug(aState);
|
||||
@@ -1475,7 +1475,7 @@ nsXULScrollFrame::GetMaxSize(nsBoxLayoutState& aState)
|
||||
|
||||
AddBorderAndPadding(maxSize);
|
||||
bool widthSet, heightSet;
|
||||
nsIFrame::AddCSSMaxSize(this, maxSize, widthSet, heightSet);
|
||||
nsIFrame::AddXULMaxSize(this, maxSize, widthSet, heightSet);
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
@@ -1488,13 +1488,13 @@ nsXULScrollFrame::GetFrameName(nsAString& aResult) const
|
||||
#endif
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXULScrollFrame::DoLayout(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::DoXULLayout(nsBoxLayoutState& aState)
|
||||
{
|
||||
uint32_t flags = aState.LayoutFlags();
|
||||
nsresult rv = Layout(aState);
|
||||
nsresult rv = XULLayout(aState);
|
||||
aState.SetLayoutFlags(flags);
|
||||
|
||||
nsBox::DoLayout(aState);
|
||||
nsBox::DoXULLayout(aState);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -4590,7 +4590,7 @@ nsXULScrollFrame::AddRemoveScrollbar(nsBoxLayoutState& aState,
|
||||
if (mHelper.mNeverHasHorizontalScrollbar || !mHelper.mHScrollbarBox)
|
||||
return false;
|
||||
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetPrefSize(aState);
|
||||
nsSize hSize = mHelper.mHScrollbarBox->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(mHelper.mHScrollbarBox, hSize);
|
||||
|
||||
mHelper.SetScrollbarVisibility(mHelper.mHScrollbarBox, aAdd);
|
||||
@@ -4609,7 +4609,7 @@ nsXULScrollFrame::AddRemoveScrollbar(nsBoxLayoutState& aState,
|
||||
if (mHelper.mNeverHasVerticalScrollbar || !mHelper.mVScrollbarBox)
|
||||
return false;
|
||||
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetPrefSize(aState);
|
||||
nsSize vSize = mHelper.mVScrollbarBox->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(mHelper.mVScrollbarBox, vSize);
|
||||
|
||||
mHelper.SetScrollbarVisibility(mHelper.mVScrollbarBox, aAdd);
|
||||
@@ -4668,7 +4668,7 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState,
|
||||
mHelper.mScrollPort.Size());
|
||||
int32_t flags = NS_FRAME_NO_MOVE_VIEW;
|
||||
|
||||
nsSize minSize = mHelper.mScrolledFrame->GetMinSize(aState);
|
||||
nsSize minSize = mHelper.mScrolledFrame->GetXULMinSize(aState);
|
||||
|
||||
if (minSize.height > childRect.height)
|
||||
childRect.height = minSize.height;
|
||||
@@ -4678,7 +4678,7 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState,
|
||||
|
||||
aState.SetLayoutFlags(flags);
|
||||
ClampAndSetBounds(aState, childRect, aScrollPosition);
|
||||
mHelper.mScrolledFrame->Layout(aState);
|
||||
mHelper.mScrolledFrame->XULLayout(aState);
|
||||
|
||||
childRect = mHelper.mScrolledFrame->GetRect();
|
||||
|
||||
@@ -4813,14 +4813,14 @@ ScrollFrameHelper::IsScrollingActive(nsDisplayListBuilder* aBuilder) const
|
||||
* cause any of the scrollbars to need to be reflowed.
|
||||
*/
|
||||
nsresult
|
||||
nsXULScrollFrame::Layout(nsBoxLayoutState& aState)
|
||||
nsXULScrollFrame::XULLayout(nsBoxLayoutState& aState)
|
||||
{
|
||||
bool scrollbarRight = IsScrollbarOnRight();
|
||||
bool scrollbarBottom = true;
|
||||
|
||||
// get the content rect
|
||||
nsRect clientRect(0,0,0,0);
|
||||
GetClientRect(clientRect);
|
||||
GetXULClientRect(clientRect);
|
||||
|
||||
nsRect oldScrollAreaBounds = mHelper.mScrollPort;
|
||||
nsPoint oldScrollPosition = mHelper.GetLogicalScrollPosition();
|
||||
@@ -5304,7 +5304,7 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
|
||||
// place the scrollcorner
|
||||
if (mScrollCornerBox || mResizerBox) {
|
||||
NS_PRECONDITION(!mScrollCornerBox || mScrollCornerBox->IsBoxFrame(), "Must be a box frame!");
|
||||
NS_PRECONDITION(!mScrollCornerBox || mScrollCornerBox->IsXULBoxFrame(), "Must be a box frame!");
|
||||
|
||||
nsRect r(0, 0, 0, 0);
|
||||
if (aContentArea.x != mScrollPort.x || scrollbarOnLeft) {
|
||||
@@ -5334,17 +5334,17 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
if (hasResizer) {
|
||||
// if a resizer is present, get its size. Assume a default size of 15 pixels.
|
||||
nscoord defaultSize = nsPresContext::CSSPixelsToAppUnits(15);
|
||||
nsSize resizerMinSize = mResizerBox->GetMinSize(aState);
|
||||
nsSize resizerMinSize = mResizerBox->GetXULMinSize(aState);
|
||||
|
||||
nscoord vScrollbarWidth = mVScrollbarBox ?
|
||||
mVScrollbarBox->GetPrefSize(aState).width : defaultSize;
|
||||
mVScrollbarBox->GetXULPrefSize(aState).width : defaultSize;
|
||||
r.width = std::max(std::max(r.width, vScrollbarWidth), resizerMinSize.width);
|
||||
if (aContentArea.x == mScrollPort.x && !scrollbarOnLeft) {
|
||||
r.x = aContentArea.XMost() - r.width;
|
||||
}
|
||||
|
||||
nscoord hScrollbarHeight = mHScrollbarBox ?
|
||||
mHScrollbarBox->GetPrefSize(aState).height : defaultSize;
|
||||
mHScrollbarBox->GetXULPrefSize(aState).height : defaultSize;
|
||||
r.height = std::max(std::max(r.height, hScrollbarHeight), resizerMinSize.height);
|
||||
if (aContentArea.y == mScrollPort.y) {
|
||||
r.y = aContentArea.YMost() - r.height;
|
||||
@@ -5361,7 +5361,7 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
nsPresContext* presContext = mScrolledFrame->PresContext();
|
||||
nsRect vRect;
|
||||
if (mVScrollbarBox) {
|
||||
NS_PRECONDITION(mVScrollbarBox->IsBoxFrame(), "Must be a box frame!");
|
||||
NS_PRECONDITION(mVScrollbarBox->IsXULBoxFrame(), "Must be a box frame!");
|
||||
vRect = mScrollPort;
|
||||
if (overlayScrollBarsWithZoom) {
|
||||
vRect.height = NSToCoordRound(res * scrollPortClampingSize.height);
|
||||
@@ -5370,7 +5370,7 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
vRect.x = scrollbarOnLeft ? aContentArea.x : mScrollPort.x + NSToCoordRound(res * scrollPortClampingSize.width);
|
||||
if (mHasVerticalScrollbar) {
|
||||
nsMargin margin;
|
||||
mVScrollbarBox->GetMargin(margin);
|
||||
mVScrollbarBox->GetXULMargin(margin);
|
||||
vRect.Deflate(margin);
|
||||
}
|
||||
AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, true);
|
||||
@@ -5378,7 +5378,7 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
|
||||
nsRect hRect;
|
||||
if (mHScrollbarBox) {
|
||||
NS_PRECONDITION(mHScrollbarBox->IsBoxFrame(), "Must be a box frame!");
|
||||
NS_PRECONDITION(mHScrollbarBox->IsXULBoxFrame(), "Must be a box frame!");
|
||||
hRect = mScrollPort;
|
||||
if (overlayScrollBarsWithZoom) {
|
||||
hRect.width = NSToCoordRound(res * scrollPortClampingSize.width);
|
||||
@@ -5387,7 +5387,7 @@ ScrollFrameHelper::LayoutScrollbars(nsBoxLayoutState& aState,
|
||||
hRect.y = mScrollPort.y + NSToCoordRound(res * scrollPortClampingSize.height);
|
||||
if (mHasHorizontalScrollbar) {
|
||||
nsMargin margin;
|
||||
mHScrollbarBox->GetMargin(margin);
|
||||
mHScrollbarBox->GetXULMargin(margin);
|
||||
hRect.Deflate(margin);
|
||||
}
|
||||
AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, false);
|
||||
|
||||
@@ -700,8 +700,8 @@ public:
|
||||
|
||||
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
|
||||
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
|
||||
virtual nsresult GetPadding(nsMargin& aPadding) override;
|
||||
virtual bool IsCollapsed() override;
|
||||
virtual nsresult GetXULPadding(nsMargin& aPadding) override;
|
||||
virtual bool IsXULCollapsed() override;
|
||||
|
||||
virtual void Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
@@ -1128,20 +1128,20 @@ public:
|
||||
virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
|
||||
uint32_t aFilter) override;
|
||||
|
||||
virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
|
||||
NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsresult GetPadding(nsMargin& aPadding) override;
|
||||
NS_IMETHOD DoXULLayout(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsresult GetXULPadding(nsMargin& aPadding) override;
|
||||
|
||||
virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
|
||||
Sides aSkipSides, nscoord aRadii[8]) const override {
|
||||
return mHelper.GetBorderRadii(aFrameSize, aBorderArea, aSkipSides, aRadii);
|
||||
}
|
||||
|
||||
nsresult Layout(nsBoxLayoutState& aState);
|
||||
nsresult XULLayout(nsBoxLayoutState& aState);
|
||||
void LayoutScrollArea(nsBoxLayoutState& aState, const nsPoint& aScrollPosition);
|
||||
|
||||
static bool AddRemoveScrollbar(bool& aHasScrollbar,
|
||||
@@ -1452,7 +1452,7 @@ protected:
|
||||
if (!mHelper.IsLTR()) {
|
||||
aRect.x = mHelper.mScrollPort.XMost() - aScrollPosition.x - aRect.width;
|
||||
}
|
||||
mHelper.mScrolledFrame->SetBounds(aState, aRect, aRemoveOverflowAreas);
|
||||
mHelper.mScrolledFrame->SetXULBounds(aState, aRect, aRemoveOverflowAreas);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "nsAlgorithm.h" // for clamped()
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSFrameConstructor.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsHashKeys.h"
|
||||
@@ -151,8 +152,21 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
|
||||
{
|
||||
MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0,
|
||||
"track size data is expected to be initialized to zero");
|
||||
auto minSizeUnit = aMinCoord.GetUnit();
|
||||
auto maxSizeUnit = aMaxCoord.GetUnit();
|
||||
if (aPercentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-percentage
|
||||
// "If the inline or block size of the grid container is indefinite,
|
||||
// <percentage> values relative to that size are treated as 'auto'."
|
||||
if (aMinCoord.HasPercent()) {
|
||||
minSizeUnit = eStyleUnit_Auto;
|
||||
}
|
||||
if (aMaxCoord.HasPercent()) {
|
||||
maxSizeUnit = eStyleUnit_Auto;
|
||||
}
|
||||
}
|
||||
// http://dev.w3.org/csswg/css-grid/#algo-init
|
||||
switch (aMinCoord.GetUnit()) {
|
||||
switch (minSizeUnit) {
|
||||
case eStyleUnit_Auto:
|
||||
mState = eAutoMinSizing;
|
||||
break;
|
||||
@@ -166,7 +180,7 @@ nsGridContainerFrame::TrackSize::Initialize(nscoord aPercentageBasis,
|
||||
default:
|
||||
mBase = nsRuleNode::ComputeCoordPercentCalc(aMinCoord, aPercentageBasis);
|
||||
}
|
||||
switch (aMaxCoord.GetUnit()) {
|
||||
switch (maxSizeUnit) {
|
||||
case eStyleUnit_Auto:
|
||||
mState |= eAutoMaxSizing;
|
||||
mLimit = NS_UNCONSTRAINEDSIZE;
|
||||
@@ -2038,12 +2052,10 @@ nsGridContainerFrame::GridReflowState::CalculateTrackSizes(
|
||||
mRows.Initialize(mRowFunctions, mGridStyle->mGridRowGap,
|
||||
aGrid.mGridRowEnd, aContentBox.BSize(mWM));
|
||||
|
||||
mIter.Reset(); // XXX cleanup this Reset mess!
|
||||
mCols.CalculateSizes(*this, mGridItems, mColFunctions,
|
||||
aContentBox.ISize(mWM), &GridArea::mCols,
|
||||
aConstraint);
|
||||
|
||||
mIter.Reset(); // XXX cleanup this Reset mess!
|
||||
mRows.CalculateSizes(*this, mGridItems, mRowFunctions,
|
||||
aContentBox.BSize(mWM), &GridArea::mRows,
|
||||
aConstraint);
|
||||
@@ -2937,6 +2949,7 @@ nsGridContainerFrame::Grid::PlaceGridItems(GridReflowState& aState,
|
||||
int32_t minCol = 1;
|
||||
int32_t minRow = 1;
|
||||
aState.mGridItems.ClearAndRetainStorage();
|
||||
aState.mIter.Reset();
|
||||
for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
|
||||
nsIFrame* child = *aState.mIter;
|
||||
GridItemInfo* info =
|
||||
@@ -3208,12 +3221,8 @@ nsGridContainerFrame::Tracks::Initialize(
|
||||
aFunctions.NumExplicitTracks());
|
||||
mSizes.SetLength(aNumTracks);
|
||||
PodZero(mSizes.Elements(), mSizes.Length());
|
||||
nscoord percentageBasis = aContentBoxSize;
|
||||
if (percentageBasis == NS_UNCONSTRAINEDSIZE) {
|
||||
percentageBasis = 0;
|
||||
}
|
||||
for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
|
||||
mSizes[i].Initialize(percentageBasis,
|
||||
mSizes[i].Initialize(aContentBoxSize,
|
||||
aFunctions.MinSizingFor(i),
|
||||
aFunctions.MaxSizingFor(i));
|
||||
}
|
||||
@@ -3485,6 +3494,7 @@ nsGridContainerFrame::Tracks::ResolveIntrinsicSize(
|
||||
const TrackSize::StateBits flexMin =
|
||||
aConstraint == nsLayoutUtils::MIN_ISIZE ? TrackSize::eFlexMinSizing
|
||||
: TrackSize::StateBits(0);
|
||||
iter.Reset();
|
||||
for (; !iter.AtEnd(); iter.Next()) {
|
||||
nsIFrame* child = *iter;
|
||||
const GridArea& area = aGridItems[iter.GridItemIndex()].mArea;
|
||||
@@ -5005,7 +5015,6 @@ nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
|
||||
grid.PlaceGridItems(gridReflowState, computedMinSize, computedSize,
|
||||
aReflowState.ComputedMaxSize());
|
||||
|
||||
gridReflowState.mIter.Reset();
|
||||
gridReflowState.CalculateTrackSizes(grid, computedSize,
|
||||
nsLayoutUtils::PREF_ISIZE);
|
||||
|
||||
@@ -5149,7 +5158,6 @@ nsGridContainerFrame::IntrinsicISize(nsRenderingContext* aRenderingContext,
|
||||
}
|
||||
state.mCols.Initialize(state.mColFunctions, state.mGridStyle->mGridColumnGap,
|
||||
grid.mGridColEnd, NS_UNCONSTRAINEDSIZE);
|
||||
state.mIter.Reset();
|
||||
state.mCols.CalculateSizes(state, state.mGridItems, state.mColFunctions,
|
||||
NS_UNCONSTRAINEDSIZE, &GridArea::mCols,
|
||||
aConstraint);
|
||||
@@ -5342,20 +5350,6 @@ nsGridContainerFrame::MergeSortedExcessOverflowContainers(nsFrameList& aList)
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool
|
||||
FrameWantsToBeInAnonymousGridItem(nsIFrame* aFrame)
|
||||
{
|
||||
// Note: This needs to match the logic in
|
||||
// nsCSSFrameConstructor::FrameConstructionItem::NeedsAnonFlexOrGridItem()
|
||||
return aFrame->IsFrameOfType(nsIFrame::eLineParticipant);
|
||||
}
|
||||
|
||||
// Debug-only override, to let us assert that our anonymous grid items are
|
||||
// set up correctly by the frame constructor -- in particular, we assert:
|
||||
// (1) we don't have any inline non-replaced children
|
||||
// (2) we don't have any consecutive anonymous grid items
|
||||
// (3) we don't have any empty anonymous grid items
|
||||
// (4) all children are on the expected child lists
|
||||
void
|
||||
nsGridContainerFrame::SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList)
|
||||
@@ -5363,25 +5357,6 @@ nsGridContainerFrame::SetInitialChildList(ChildListID aListID,
|
||||
ChildListIDs supportedLists = kAbsoluteList | kFixedList | kPrincipalList;
|
||||
MOZ_ASSERT(supportedLists.Contains(aListID), "unexpected child list");
|
||||
|
||||
if (aListID == kPrincipalList) {
|
||||
bool prevChildWasAnonGridItem = false;
|
||||
for (nsFrameList::Enumerator e(aChildList); !e.AtEnd(); e.Next()) {
|
||||
nsIFrame* child = e.get();
|
||||
MOZ_ASSERT(!FrameWantsToBeInAnonymousGridItem(child),
|
||||
"frame wants to be inside an anonymous grid item, but it isn't");
|
||||
if (child->StyleContext()->GetPseudo() ==
|
||||
nsCSSAnonBoxes::anonymousGridItem) {
|
||||
MOZ_ASSERT(!prevChildWasAnonGridItem, "two anon grid items in a row");
|
||||
nsIFrame* firstWrappedChild = child->PrincipalChildList().FirstChild();
|
||||
MOZ_ASSERT(firstWrappedChild,
|
||||
"anonymous grid item is empty (shouldn't happen)");
|
||||
prevChildWasAnonGridItem = true;
|
||||
} else {
|
||||
prevChildWasAnonGridItem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsContainerFrame::SetInitialChildList(aListID, aChildList);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#ifndef nsGridContainerFrame_h___
|
||||
#define nsGridContainerFrame_h___
|
||||
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsHashKeys.h"
|
||||
@@ -46,6 +47,7 @@ public:
|
||||
NS_DECL_FRAMEARENA_HELPERS
|
||||
NS_DECL_QUERYFRAME_TARGET(nsGridContainerFrame)
|
||||
NS_DECL_QUERYFRAME
|
||||
typedef mozilla::ComputedGridTrackInfo ComputedGridTrackInfo;
|
||||
|
||||
// nsIFrame overrides
|
||||
void Reflow(nsPresContext* aPresContext,
|
||||
@@ -202,7 +204,7 @@ private:
|
||||
bool mIsAutoBSize;
|
||||
};
|
||||
|
||||
Maybe<nsGridContainerFrame::Fragmentainer>
|
||||
mozilla::Maybe<nsGridContainerFrame::Fragmentainer>
|
||||
GetNearestFragmentainer(const GridReflowState& aState) const;
|
||||
|
||||
// @return the consumed size of all continuations so far including this frame
|
||||
|
||||
@@ -665,7 +665,7 @@ nsHTMLReflowState::InitResizeFlags(nsPresContext* aPresContext, nsIAtom* aFrameT
|
||||
mStylePosition->MaxBSizeDependsOnContainer(wm) ||
|
||||
mStylePosition->OffsetHasPercent(wm.PhysicalSide(eLogicalSideBStart)) ||
|
||||
mStylePosition->mOffset.GetBEndUnit(wm) != eStyleUnit_Auto ||
|
||||
frame->IsBoxFrame();
|
||||
frame->IsXULBoxFrame();
|
||||
|
||||
if (mStyleText->mLineHeight.GetUnit() == eStyleUnit_Enumerated) {
|
||||
NS_ASSERTION(mStyleText->mLineHeight.GetIntValue() ==
|
||||
|
||||
+41
-49
@@ -2107,7 +2107,6 @@ public:
|
||||
*/
|
||||
bool HasView() const { return !!(mState & NS_FRAME_HAS_VIEW); }
|
||||
nsView* GetView() const;
|
||||
virtual nsView* GetViewExternal() const;
|
||||
nsresult SetView(nsView* aView);
|
||||
|
||||
/**
|
||||
@@ -2121,7 +2120,6 @@ public:
|
||||
* Find the closest ancestor (excluding |this| !) that has a view
|
||||
*/
|
||||
nsIFrame* GetAncestorWithView() const;
|
||||
virtual nsIFrame* GetAncestorWithViewExternal() const;
|
||||
|
||||
/**
|
||||
* Get the offset between the coordinate systems of |this| and aOther.
|
||||
@@ -2140,7 +2138,6 @@ public:
|
||||
* aOther.
|
||||
*/
|
||||
nsPoint GetOffsetTo(const nsIFrame* aOther) const;
|
||||
virtual nsPoint GetOffsetToExternal(const nsIFrame* aOther) const;
|
||||
|
||||
/**
|
||||
* Get the offset between the coordinate systems of |this| and aOther
|
||||
@@ -2175,14 +2172,12 @@ public:
|
||||
* @return the pixel rect of the frame in screen coordinates.
|
||||
*/
|
||||
nsIntRect GetScreenRect() const;
|
||||
virtual nsIntRect GetScreenRectExternal() const;
|
||||
|
||||
/**
|
||||
* Get the screen rect of the frame in app units.
|
||||
* @return the app unit rect of the frame in screen coordinates.
|
||||
*/
|
||||
nsRect GetScreenRectInAppUnits() const;
|
||||
virtual nsRect GetScreenRectInAppUnitsExternal() const;
|
||||
|
||||
/**
|
||||
* Returns the offset from this frame to the closest geometric parent that
|
||||
@@ -2195,16 +2190,15 @@ public:
|
||||
* view and the view has a widget, then this frame's widget is
|
||||
* returned, otherwise this frame's geometric parent is checked
|
||||
* recursively upwards.
|
||||
* XXX virtual because gfx callers use it! (themes)
|
||||
*/
|
||||
virtual nsIWidget* GetNearestWidget() const;
|
||||
nsIWidget* GetNearestWidget() const;
|
||||
|
||||
/**
|
||||
* Same as GetNearestWidget() above but uses an outparam to return the offset
|
||||
* of this frame to the returned widget expressed in appunits of |this| (the
|
||||
* widget might be in a different document with a different zoom).
|
||||
*/
|
||||
virtual nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
|
||||
nsIWidget* GetNearestWidget(nsPoint& aOffset) const;
|
||||
|
||||
/**
|
||||
* Get the "type" of the frame. May return nullptr.
|
||||
@@ -2868,7 +2862,7 @@ public:
|
||||
// BOX LAYOUT METHODS
|
||||
// These methods have been migrated from nsIBox and are in the process of
|
||||
// being refactored. DO NOT USE OUTSIDE OF XUL.
|
||||
bool IsBoxFrame() const
|
||||
bool IsXULBoxFrame() const
|
||||
{
|
||||
return IsFrameOfType(nsIFrame::eXULBox);
|
||||
}
|
||||
@@ -2891,87 +2885,85 @@ public:
|
||||
* @param[in] aBoxLayoutState The desired state to calculate for
|
||||
* @return The minimum size
|
||||
*/
|
||||
virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
|
||||
/**
|
||||
* This calculates the preferred size of a box based on its state
|
||||
* @param[in] aBoxLayoutState The desired state to calculate for
|
||||
* @return The preferred size
|
||||
*/
|
||||
virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
|
||||
/**
|
||||
* This calculates the maximum size for a box based on its state
|
||||
* @param[in] aBoxLayoutState The desired state to calculate for
|
||||
* @return The maximum size
|
||||
*/
|
||||
virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
|
||||
/**
|
||||
* This returns the minimum size for the scroll area if this frame is
|
||||
* being scrolled. Usually it's (0,0).
|
||||
*/
|
||||
virtual nsSize GetMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual nsSize GetXULMinSizeForScrollArea(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
|
||||
// Implemented in nsBox, used in nsBoxFrame
|
||||
uint32_t GetOrdinal();
|
||||
uint32_t GetXULOrdinal();
|
||||
|
||||
virtual nscoord GetFlex() = 0;
|
||||
virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual bool IsCollapsed() = 0;
|
||||
virtual nscoord GetXULFlex() = 0;
|
||||
virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) = 0;
|
||||
virtual bool IsXULCollapsed() = 0;
|
||||
// This does not alter the overflow area. If the caller is changing
|
||||
// the box size, the caller is responsible for updating the overflow
|
||||
// area. It's enough to just call Layout or SyncLayout on the
|
||||
// area. It's enough to just call XULLayout or SyncLayout on the
|
||||
// box. You can pass true to aRemoveOverflowArea as a
|
||||
// convenience.
|
||||
virtual void SetBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
|
||||
bool aRemoveOverflowAreas = false) = 0;
|
||||
nsresult Layout(nsBoxLayoutState& aBoxLayoutState);
|
||||
virtual void SetXULBounds(nsBoxLayoutState& aBoxLayoutState, const nsRect& aRect,
|
||||
bool aRemoveOverflowAreas = false) = 0;
|
||||
nsresult XULLayout(nsBoxLayoutState& aBoxLayoutState);
|
||||
// Box methods. Note that these do NOT just get the CSS border, padding,
|
||||
// etc. They also talk to nsITheme.
|
||||
virtual nsresult GetBorderAndPadding(nsMargin& aBorderAndPadding);
|
||||
virtual nsresult GetBorder(nsMargin& aBorder)=0;
|
||||
virtual nsresult GetPadding(nsMargin& aBorderAndPadding)=0;
|
||||
virtual nsresult GetMargin(nsMargin& aMargin)=0;
|
||||
virtual void SetLayoutManager(nsBoxLayout* aLayout) { }
|
||||
virtual nsBoxLayout* GetLayoutManager() { return nullptr; }
|
||||
nsresult GetClientRect(nsRect& aContentRect);
|
||||
virtual nsresult GetXULBorderAndPadding(nsMargin& aBorderAndPadding);
|
||||
virtual nsresult GetXULBorder(nsMargin& aBorder)=0;
|
||||
virtual nsresult GetXULPadding(nsMargin& aBorderAndPadding)=0;
|
||||
virtual nsresult GetXULMargin(nsMargin& aMargin)=0;
|
||||
virtual void SetXULLayoutManager(nsBoxLayout* aLayout) { }
|
||||
virtual nsBoxLayout* GetXULLayoutManager() { return nullptr; }
|
||||
nsresult GetXULClientRect(nsRect& aContentRect);
|
||||
|
||||
// For nsSprocketLayout
|
||||
virtual Valignment GetVAlign() const = 0;
|
||||
virtual Halignment GetHAlign() const = 0;
|
||||
virtual Valignment GetXULVAlign() const = 0;
|
||||
virtual Halignment GetXULHAlign() const = 0;
|
||||
|
||||
bool IsHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; }
|
||||
bool IsNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; }
|
||||
bool IsXULHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; }
|
||||
bool IsXULNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; }
|
||||
|
||||
nsresult Redraw(nsBoxLayoutState& aState);
|
||||
virtual nsresult RelayoutChildAtOrdinal(nsIFrame* aChild)=0;
|
||||
// XXX take this out after we've branched
|
||||
virtual bool GetMouseThrough() const { return false; }
|
||||
nsresult XULRedraw(nsBoxLayoutState& aState);
|
||||
virtual nsresult XULRelayoutChildAtOrdinal(nsIFrame* aChild)=0;
|
||||
|
||||
#ifdef DEBUG_LAYOUT
|
||||
virtual nsresult SetDebug(nsBoxLayoutState& aState, bool aDebug)=0;
|
||||
virtual nsresult GetDebug(bool& aDebug)=0;
|
||||
virtual nsresult SetXULDebug(nsBoxLayoutState& aState, bool aDebug)=0;
|
||||
virtual nsresult GetXULDebug(bool& aDebug)=0;
|
||||
|
||||
virtual nsresult DumpBox(FILE* out)=0;
|
||||
virtual nsresult XULDumpBox(FILE* out)=0;
|
||||
#endif
|
||||
|
||||
static bool AddXULPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddXULMinSize(nsBoxLayoutState& aState, nsIFrame* aBox,
|
||||
nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddXULMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddXULFlex(nsIFrame* aBox, nscoord& aFlex);
|
||||
|
||||
// END OF BOX LAYOUT METHODS
|
||||
// The above methods have been migrated from nsIBox and are in the process of
|
||||
// being refactored. DO NOT USE OUTSIDE OF XUL.
|
||||
|
||||
/**
|
||||
* @return true if this text frame ends with a newline character. It
|
||||
* should return false if this is not a text frame.
|
||||
*/
|
||||
virtual bool HasSignificantTerminalNewline() const;
|
||||
|
||||
static bool AddCSSPrefSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddCSSMinSize(nsBoxLayoutState& aState, nsIFrame* aBox,
|
||||
nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddCSSMaxSize(nsIFrame* aBox, nsSize& aSize, bool& aWidth, bool& aHeightSet);
|
||||
static bool AddCSSFlex(nsIFrame* aBox, nscoord& aFlex);
|
||||
|
||||
// END OF BOX LAYOUT METHODS
|
||||
// The above methods have been migrated from nsIBox and are in the process of
|
||||
// being refactored. DO NOT USE OUTSIDE OF XUL.
|
||||
|
||||
struct CaretPosition {
|
||||
CaretPosition();
|
||||
~CaretPosition();
|
||||
|
||||
@@ -1524,64 +1524,18 @@ nsDisplayImage::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
|
||||
nsDisplayImageContainer::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayImage::CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder)
|
||||
already_AddRefed<imgIContainer>
|
||||
nsDisplayImage::GetImage()
|
||||
{
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
if (!mImage->IsImageContainerAvailable(aManager, flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t imageWidth;
|
||||
int32_t imageHeight;
|
||||
mImage->GetWidth(&imageWidth);
|
||||
mImage->GetHeight(&imageHeight);
|
||||
|
||||
if (imageWidth == 0 || imageHeight == 0) {
|
||||
NS_ASSERTION(false, "invalid image size");
|
||||
return false;
|
||||
}
|
||||
|
||||
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
const LayoutDeviceRect destRect =
|
||||
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
||||
|
||||
// Calculate the scaling factor for the frame.
|
||||
const gfxSize scale = gfxSize(destRect.width / imageWidth,
|
||||
destRect.height / imageHeight);
|
||||
|
||||
if (scale.width < 0.2 || scale.height < 0.2) {
|
||||
// This would look awful as long as we can't use high-quality downscaling
|
||||
// for image layers (bug 803703), so don't turn this into an image layer.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<ImageContainer>
|
||||
nsDisplayImage::GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
uint32_t flags = aBuilder->ShouldSyncDecodeImages()
|
||||
? imgIContainer::FLAG_SYNC_DECODE
|
||||
: imgIContainer::FLAG_NONE;
|
||||
|
||||
return mImage->GetImageContainer(aManager, flags);
|
||||
nsCOMPtr<imgIContainer> image = mImage;
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsDisplayImage::GetDestRect(bool* aSnap)
|
||||
nsDisplayImage::GetDestRect()
|
||||
{
|
||||
bool snap = true;
|
||||
const nsRect frameContentBox = GetBounds(&snap);
|
||||
if (aSnap) {
|
||||
*aSnap = snap;
|
||||
}
|
||||
|
||||
nsImageFrame* imageFrame = static_cast<nsImageFrame*>(mFrame);
|
||||
return imageFrame->PredictedDestRect(frameContentBox);
|
||||
@@ -1682,54 +1636,6 @@ nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayImage::ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters)
|
||||
{
|
||||
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
|
||||
|
||||
int32_t imageWidth;
|
||||
int32_t imageHeight;
|
||||
mImage->GetWidth(&imageWidth);
|
||||
mImage->GetHeight(&imageHeight);
|
||||
|
||||
NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!");
|
||||
if (imageWidth > 0 && imageHeight > 0) {
|
||||
// We're actually using the ImageContainer. Let our frame know that it
|
||||
// should consider itself to have painted successfully.
|
||||
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this,
|
||||
DrawResult::SUCCESS);
|
||||
}
|
||||
|
||||
const int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
const LayoutDeviceRect destRect =
|
||||
LayoutDeviceRect::FromAppUnits(GetDestRect(), factor);
|
||||
|
||||
// XXX(seth): Right now we ignore aParameters.Scale() and
|
||||
// aParameters.Offset(), because FrameLayerBuilder already applies
|
||||
// aParameters.Scale() via the layer's post-transform, and
|
||||
// aParameters.Offset() is always zero.
|
||||
MOZ_ASSERT(aParameters.Offset() == LayerIntPoint(0,0));
|
||||
|
||||
// It's possible (for example, due to downscale-during-decode) that the
|
||||
// ImageContainer this ImageLayer is holding has a different size from the
|
||||
// intrinsic size of the image. For this reason we compute the transform using
|
||||
// the ImageContainer's size rather than the image's intrinsic size.
|
||||
// XXX(seth): In reality, since the size of the ImageContainer may change
|
||||
// asynchronously, this is not enough. Bug 1183378 will provide a more
|
||||
// complete fix, but this solution is safe in more cases than simply relying
|
||||
// on the intrinsic size.
|
||||
IntSize containerSize = aLayer->GetContainer()
|
||||
? aLayer->GetContainer()->GetCurrentSize()
|
||||
: IntSize(imageWidth, imageHeight);
|
||||
|
||||
const LayoutDevicePoint p = destRect.TopLeft();
|
||||
Matrix transform = Matrix::Translation(p.x, p.y);
|
||||
transform.PreScale(destRect.Width() / containerSize.width,
|
||||
destRect.Height() / containerSize.height);
|
||||
aLayer->SetBaseTransform(gfx::Matrix4x4::From2D(transform));
|
||||
}
|
||||
|
||||
DrawResult
|
||||
nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt,
|
||||
const nsRect& aDirtyRect, imgIContainer* aImage,
|
||||
@@ -2265,6 +2171,7 @@ nsImageFrame::LoadIcon(const nsAString& aSpec,
|
||||
nullptr, /* principal (not relevant for icons) */
|
||||
loadGroup,
|
||||
gIconLoad,
|
||||
nullptr, /* No context */
|
||||
nullptr, /* Not associated with any particular document */
|
||||
loadFlags,
|
||||
nullptr,
|
||||
|
||||
@@ -428,21 +428,13 @@ public:
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) override;
|
||||
|
||||
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder) override;
|
||||
|
||||
/**
|
||||
* Returns an ImageContainer for this image if the image type
|
||||
* supports it (TYPE_RASTER only).
|
||||
*/
|
||||
virtual already_AddRefed<ImageContainer> GetContainer(LayerManager* aManager,
|
||||
nsDisplayListBuilder* aBuilder) override;
|
||||
virtual already_AddRefed<imgIContainer> GetImage() override;
|
||||
|
||||
/**
|
||||
* @return The dest rect we'll use when drawing this image, in app units.
|
||||
* Not necessarily contained in this item's bounds.
|
||||
*/
|
||||
nsRect GetDestRect(bool* aSnap = nullptr);
|
||||
virtual nsRect GetDestRect() override;
|
||||
|
||||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
@@ -468,13 +460,6 @@ public:
|
||||
LayerManager* aManager,
|
||||
const ContainerLayerParameters& aContainerParameters) override;
|
||||
|
||||
/**
|
||||
* Configure an ImageLayer for this display item.
|
||||
* Set the required filter and scaling transform.
|
||||
*/
|
||||
virtual void ConfigureLayer(ImageLayer* aLayer,
|
||||
const ContainerLayerParameters& aParameters) override;
|
||||
|
||||
NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
|
||||
private:
|
||||
nsCOMPtr<imgIContainer> mImage;
|
||||
|
||||
@@ -38,7 +38,7 @@ NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
|
||||
#endif
|
||||
|
||||
/* virtual */ nsSize
|
||||
nsPlaceholderFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
nsPlaceholderFrame::GetXULMinSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
{
|
||||
nsSize size(0, 0);
|
||||
DISPLAY_MIN_SIZE(this, size);
|
||||
@@ -46,7 +46,7 @@ nsPlaceholderFrame::GetMinSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
}
|
||||
|
||||
/* virtual */ nsSize
|
||||
nsPlaceholderFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
nsPlaceholderFrame::GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
{
|
||||
nsSize size(0, 0);
|
||||
DISPLAY_PREF_SIZE(this, size);
|
||||
@@ -54,7 +54,7 @@ nsPlaceholderFrame::GetPrefSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
}
|
||||
|
||||
/* virtual */ nsSize
|
||||
nsPlaceholderFrame::GetMaxSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
nsPlaceholderFrame::GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState)
|
||||
{
|
||||
nsSize size(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
|
||||
DISPLAY_MAX_SIZE(this, size);
|
||||
|
||||
@@ -88,15 +88,15 @@ public:
|
||||
}
|
||||
|
||||
// nsIFrame overrides
|
||||
// We need to override GetMinSize and GetPrefSize because XUL uses
|
||||
// We need to override GetXULMinSize and GetXULPrefSize because XUL uses
|
||||
// placeholders not within lines.
|
||||
virtual void AddInlineMinISize(nsRenderingContext* aRenderingContext,
|
||||
InlineMinISizeData* aData) override;
|
||||
virtual void AddInlinePrefISize(nsRenderingContext* aRenderingContext,
|
||||
InlinePrefISizeData* aData) override;
|
||||
virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState) override;
|
||||
|
||||
virtual void Reflow(nsPresContext* aPresContext,
|
||||
nsHTMLReflowMetrics& aDesiredSize,
|
||||
|
||||
@@ -610,7 +610,7 @@ nsVideoFrame::GetVideoIntrinsicSize(nsRenderingContext *aRenderingContext)
|
||||
|
||||
// Ask the controls frame what its preferred height is
|
||||
nsBoxLayoutState boxState(PresContext(), aRenderingContext, 0);
|
||||
nscoord prefHeight = mFrames.LastChild()->GetPrefSize(boxState).height;
|
||||
nscoord prefHeight = mFrames.LastChild()->GetXULPrefSize(boxState).height;
|
||||
return nsSize(nsPresContext::CSSPixelsToAppUnits(size.width), prefHeight);
|
||||
}
|
||||
|
||||
|
||||
@@ -263,7 +263,8 @@ ImageLoader::LoadImage(nsIURI* aURI, nsIPrincipal* aOriginPrincipal,
|
||||
}
|
||||
|
||||
RefPtr<imgRequestProxy> request;
|
||||
nsContentUtils::LoadImage(aURI, mDocument, aOriginPrincipal, aReferrer,
|
||||
nsContentUtils::LoadImage(aURI, mDocument, mDocument,
|
||||
aOriginPrincipal, aReferrer,
|
||||
mDocument->GetReferrerPolicy(),
|
||||
nullptr, nsIRequest::LOAD_NORMAL,
|
||||
NS_LITERAL_STRING("css"),
|
||||
|
||||
@@ -800,3 +800,19 @@ nsTransitionManager::PruneCompletedTransitions(mozilla::dom::Element* aElement,
|
||||
collection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTransitionManager::StopTransitionsForElement(
|
||||
mozilla::dom::Element* aElement,
|
||||
mozilla::CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
CSSTransitionCollection* collection =
|
||||
CSSTransitionCollection::GetAnimationCollection(aElement, aPseudoType);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
|
||||
collection->Destroy();
|
||||
}
|
||||
|
||||
@@ -339,6 +339,12 @@ public:
|
||||
void SortEvents() { mEventDispatcher.SortEvents(); }
|
||||
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
|
||||
|
||||
// Stop transitions on the element. This method takes the real element
|
||||
// rather than the element for the generated content for transitions on
|
||||
// ::before and ::after.
|
||||
void StopTransitionsForElement(mozilla::dom::Element* aElement,
|
||||
mozilla::CSSPseudoElementType aPseudoType);
|
||||
|
||||
protected:
|
||||
virtual ~nsTransitionManager() {}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ static nsIFrame* GetScrolledBox(BoxObject* aScrollBox) {
|
||||
nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
|
||||
if (!scrolledFrame)
|
||||
return nullptr;
|
||||
return nsBox::GetChildBox(scrolledFrame);
|
||||
return nsBox::GetChildXULBox(scrolledFrame);
|
||||
}
|
||||
|
||||
void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
@@ -112,13 +112,13 @@ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
nsRect rect;
|
||||
|
||||
// now get the scrolled boxes first child.
|
||||
nsIFrame* child = nsBox::GetChildBox(scrolledBox);
|
||||
nsIFrame* child = nsBox::GetChildXULBox(scrolledBox);
|
||||
|
||||
bool horiz = scrolledBox->IsHorizontal();
|
||||
bool horiz = scrolledBox->IsXULHorizontal();
|
||||
nsPoint cp = sf->GetScrollPosition();
|
||||
nscoord diff = 0;
|
||||
int32_t curIndex = 0;
|
||||
bool isLTR = scrolledBox->IsNormalDirection();
|
||||
bool isLTR = scrolledBox->IsXULNormalDirection();
|
||||
|
||||
int32_t frameWidth = 0;
|
||||
if (!isLTR && horiz) {
|
||||
@@ -152,7 +152,7 @@ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
child = nsBox::GetNextBox(child);
|
||||
child = nsBox::GetNextXULBox(child);
|
||||
curIndex++;
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
|
||||
if (dindexes > 0) {
|
||||
while(child) {
|
||||
child = nsBox::GetNextBox(child);
|
||||
child = nsBox::GetNextXULBox(child);
|
||||
if (child) {
|
||||
rect = child->GetRect();
|
||||
}
|
||||
@@ -174,7 +174,7 @@ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
} else if (dindexes < 0) {
|
||||
child = nsBox::GetChildBox(scrolledBox);
|
||||
child = nsBox::GetChildXULBox(scrolledBox);
|
||||
while(child) {
|
||||
rect = child->GetRect();
|
||||
if (count >= curIndex + dindexes) {
|
||||
@@ -182,7 +182,7 @@ void ScrollBoxObject::ScrollByIndex(int32_t dindexes, ErrorResult& aRv)
|
||||
}
|
||||
|
||||
count++;
|
||||
child = nsBox::GetNextBox(child);
|
||||
child = nsBox::GetNextXULBox(child);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+40
-40
@@ -245,7 +245,7 @@ nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
|
||||
nsIFrame* child = nullptr;
|
||||
// if we have <grid></grid> then mBox will be null (bug 125689)
|
||||
if (mBox)
|
||||
child = nsBox::GetChildBox(mBox);
|
||||
child = nsBox::GetChildXULBox(mBox);
|
||||
|
||||
while(child)
|
||||
{
|
||||
@@ -262,7 +262,7 @@ nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
|
||||
{
|
||||
nsGridRowGroupLayout* rowGroup = monument->CastToRowGroupLayout();
|
||||
if (rowGroup) {
|
||||
bool isHorizontal = !nsSprocketLayout::IsHorizontal(child);
|
||||
bool isHorizontal = !nsSprocketLayout::IsXULHorizontal(child);
|
||||
if (isHorizontal)
|
||||
*aRows = child;
|
||||
else
|
||||
@@ -277,7 +277,7 @@ nsGrid::FindRowsAndColumns(nsIFrame** aRows, nsIFrame** aColumns)
|
||||
child = oldBox;
|
||||
}
|
||||
|
||||
child = nsBox::GetNextBox(child);
|
||||
child = nsBox::GetNextXULBox(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,7 +397,7 @@ nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, int32_t aRowCount
|
||||
|
||||
child = row->mBox;
|
||||
if (child) {
|
||||
child = nsBox::GetChildBox(child);
|
||||
child = nsBox::GetChildXULBox(child);
|
||||
|
||||
j = 0;
|
||||
|
||||
@@ -416,7 +416,7 @@ nsGrid::PopulateCellMap(nsGridRow* aRows, nsGridRow* aColumns, int32_t aRowCount
|
||||
else
|
||||
GetCellAt(i,j)->SetBoxInColumn(child);
|
||||
|
||||
child = nsBox::GetNextBox(child);
|
||||
child = nsBox::GetNextXULBox(child);
|
||||
|
||||
j++;
|
||||
}
|
||||
@@ -543,7 +543,7 @@ nsGrid::GetPartFromBox(nsIFrame* aBox)
|
||||
if (!aBox)
|
||||
return nullptr;
|
||||
|
||||
nsBoxLayout* layout = aBox->GetLayoutManager();
|
||||
nsBoxLayout* layout = aBox->GetXULLayoutManager();
|
||||
return layout ? layout->AsGridPart() : nullptr;
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ nsGrid::GetFirstAndLastRow(int32_t& aFirstIndex,
|
||||
for (i=0; i < count; i++)
|
||||
{
|
||||
nsGridRow* row = GetRowAt(i,aIsHorizontal);
|
||||
if (!row->IsCollapsed()) {
|
||||
if (!row->IsXULCollapsed()) {
|
||||
aFirstIndex = i;
|
||||
aFirstRow = row;
|
||||
break;
|
||||
@@ -609,7 +609,7 @@ nsGrid::GetFirstAndLastRow(int32_t& aFirstIndex,
|
||||
for (i=count-1; i >= 0; i--)
|
||||
{
|
||||
nsGridRow* row = GetRowAt(i,aIsHorizontal);
|
||||
if (!row->IsCollapsed()) {
|
||||
if (!row->IsXULCollapsed()) {
|
||||
aLastIndex = i;
|
||||
aLastRow = row;
|
||||
break;
|
||||
@@ -652,13 +652,13 @@ nsGrid::GetRowOffsets(int32_t aIndex, nscoord& aTop, nscoord& aBottom, bool aIsH
|
||||
// borders padding into account
|
||||
if (box && !row->mIsBogus)
|
||||
{
|
||||
if (!box->IsCollapsed())
|
||||
if (!box->IsXULCollapsed())
|
||||
{
|
||||
// get real border and padding. GetBorderAndPadding
|
||||
// get real border and padding. GetXULBorderAndPadding
|
||||
// is redefined on nsGridRowLeafFrame. If we called it here
|
||||
// we would be in finite recurson.
|
||||
box->GetBorder(border);
|
||||
box->GetPadding(padding);
|
||||
box->GetXULBorder(border);
|
||||
box->GetXULPadding(padding);
|
||||
|
||||
totalBorderPadding += border;
|
||||
totalBorderPadding += padding;
|
||||
@@ -717,17 +717,17 @@ nsGrid::GetRowOffsets(int32_t aIndex, nscoord& aTop, nscoord& aBottom, bool aIsH
|
||||
if (box)
|
||||
{
|
||||
// ignore collapsed children
|
||||
if (!box->IsCollapsed())
|
||||
if (!box->IsXULCollapsed())
|
||||
{
|
||||
// include the margin of the columns. To the row
|
||||
// at this point border/padding and margins all added
|
||||
// up to more needed space.
|
||||
margin = GetBoxTotalMargin(box, !aIsHorizontal);
|
||||
// get real border and padding. GetBorderAndPadding
|
||||
// get real border and padding. GetXULBorderAndPadding
|
||||
// is redefined on nsGridRowLeafFrame. If we called it here
|
||||
// we would be in finite recurson.
|
||||
box->GetBorder(border);
|
||||
box->GetPadding(padding);
|
||||
box->GetXULBorder(border);
|
||||
box->GetXULPadding(padding);
|
||||
totalChildBorderPadding += border;
|
||||
totalChildBorderPadding += padding;
|
||||
totalChildBorderPadding += margin;
|
||||
@@ -792,7 +792,7 @@ nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHoriz
|
||||
|
||||
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
||||
|
||||
if (row->IsCollapsed())
|
||||
if (row->IsXULCollapsed())
|
||||
return 0;
|
||||
|
||||
if (row->IsPrefSet())
|
||||
@@ -805,7 +805,7 @@ nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHoriz
|
||||
{
|
||||
bool widthSet, heightSet;
|
||||
nsSize cssSize(-1, -1);
|
||||
nsIFrame::AddCSSPrefSize(box, cssSize, widthSet, heightSet);
|
||||
nsIFrame::AddXULPrefSize(box, cssSize, widthSet, heightSet);
|
||||
|
||||
row->mPref = GET_HEIGHT(cssSize, aIsHorizontal);
|
||||
|
||||
@@ -826,7 +826,7 @@ nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHoriz
|
||||
nsSize size(0,0);
|
||||
if (box)
|
||||
{
|
||||
size = box->GetPrefSize(aState);
|
||||
size = box->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(box, size);
|
||||
nsGridLayout2::AddOffset(box, size);
|
||||
}
|
||||
@@ -849,9 +849,9 @@ nsGrid::GetPrefRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHoriz
|
||||
child = GetCellAt(aIndex,i);
|
||||
|
||||
// ignore collapsed children
|
||||
if (!child->IsCollapsed())
|
||||
if (!child->IsXULCollapsed())
|
||||
{
|
||||
nsSize childSize = child->GetPrefSize(aState);
|
||||
nsSize childSize = child->GetXULPrefSize(aState);
|
||||
|
||||
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
||||
}
|
||||
@@ -869,7 +869,7 @@ nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
|
||||
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
||||
|
||||
if (row->IsCollapsed())
|
||||
if (row->IsXULCollapsed())
|
||||
return 0;
|
||||
|
||||
if (row->IsMinSet())
|
||||
@@ -881,7 +881,7 @@ nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
if (box) {
|
||||
bool widthSet, heightSet;
|
||||
nsSize cssSize(-1, -1);
|
||||
nsIFrame::AddCSSMinSize(aState, box, cssSize, widthSet, heightSet);
|
||||
nsIFrame::AddXULMinSize(aState, box, cssSize, widthSet, heightSet);
|
||||
|
||||
row->mMin = GET_HEIGHT(cssSize, aIsHorizontal);
|
||||
|
||||
@@ -901,7 +901,7 @@ nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
{
|
||||
nsSize size(0,0);
|
||||
if (box) {
|
||||
size = box->GetPrefSize(aState);
|
||||
size = box->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(box, size);
|
||||
nsGridLayout2::AddOffset(box, size);
|
||||
}
|
||||
@@ -924,9 +924,9 @@ nsGrid::GetMinRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
child = GetCellAt(aIndex,i);
|
||||
|
||||
// ignore collapsed children
|
||||
if (!child->IsCollapsed())
|
||||
if (!child->IsXULCollapsed())
|
||||
{
|
||||
nsSize childSize = child->GetMinSize(aState);
|
||||
nsSize childSize = child->GetXULMinSize(aState);
|
||||
|
||||
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
||||
}
|
||||
@@ -944,7 +944,7 @@ nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
|
||||
nsGridRow* row = GetRowAt(aIndex, aIsHorizontal);
|
||||
|
||||
if (row->IsCollapsed())
|
||||
if (row->IsXULCollapsed())
|
||||
return 0;
|
||||
|
||||
if (row->IsMaxSet())
|
||||
@@ -956,7 +956,7 @@ nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
if (box) {
|
||||
bool widthSet, heightSet;
|
||||
nsSize cssSize(-1, -1);
|
||||
nsIFrame::AddCSSMaxSize(box, cssSize, widthSet, heightSet);
|
||||
nsIFrame::AddXULMaxSize(box, cssSize, widthSet, heightSet);
|
||||
|
||||
row->mMax = GET_HEIGHT(cssSize, aIsHorizontal);
|
||||
|
||||
@@ -976,7 +976,7 @@ nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
{
|
||||
nsSize size(NS_INTRINSICSIZE,NS_INTRINSICSIZE);
|
||||
if (box) {
|
||||
size = box->GetPrefSize(aState);
|
||||
size = box->GetXULPrefSize(aState);
|
||||
nsBox::AddMargin(box, size);
|
||||
nsGridLayout2::AddOffset(box, size);
|
||||
}
|
||||
@@ -999,10 +999,10 @@ nsGrid::GetMaxRowHeight(nsBoxLayoutState& aState, int32_t aIndex, bool aIsHorizo
|
||||
child = GetCellAt(aIndex,i);
|
||||
|
||||
// ignore collapsed children
|
||||
if (!child->IsCollapsed())
|
||||
if (!child->IsXULCollapsed())
|
||||
{
|
||||
nsSize min = child->GetMinSize(aState);
|
||||
nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetMaxSize(aState));
|
||||
nsSize min = child->GetXULMinSize(aState);
|
||||
nsSize childSize = nsBox::BoundsCheckMinMax(min, child->GetXULMaxSize(aState));
|
||||
nsSprocketLayout::AddLargestSize(size, childSize, aIsHorizontal);
|
||||
}
|
||||
}
|
||||
@@ -1092,21 +1092,21 @@ nsGrid::GetRowFlex(int32_t aIndex, bool aIsHorizontal)
|
||||
// the grid. 3) Then we are not flexible
|
||||
|
||||
box = GetScrollBox(box);
|
||||
nsIFrame* parent = nsBox::GetParentBox(box);
|
||||
nsIFrame* parent = nsBox::GetParentXULBox(box);
|
||||
nsIFrame* parentsParent=nullptr;
|
||||
|
||||
while(parent)
|
||||
{
|
||||
parent = GetScrollBox(parent);
|
||||
parentsParent = nsBox::GetParentBox(parent);
|
||||
parentsParent = nsBox::GetParentXULBox(parent);
|
||||
|
||||
// if our parents parent is not a grid
|
||||
// the get its flex. If its 0 then we are
|
||||
// not flexible.
|
||||
if (parentsParent) {
|
||||
if (!IsGrid(parentsParent)) {
|
||||
nscoord flex = parent->GetFlex();
|
||||
nsIFrame::AddCSSFlex(parent, flex);
|
||||
nscoord flex = parent->GetXULFlex();
|
||||
nsIFrame::AddXULFlex(parent, flex);
|
||||
if (flex == 0) {
|
||||
row->mFlex = 0;
|
||||
return row->mFlex;
|
||||
@@ -1119,8 +1119,8 @@ nsGrid::GetRowFlex(int32_t aIndex, bool aIsHorizontal)
|
||||
}
|
||||
|
||||
// get the row flex.
|
||||
row->mFlex = box->GetFlex();
|
||||
nsIFrame::AddCSSFlex(box, row->mFlex);
|
||||
row->mFlex = box->GetXULFlex();
|
||||
nsIFrame::AddXULFlex(box, row->mFlex);
|
||||
}
|
||||
|
||||
return row->mFlex;
|
||||
@@ -1225,7 +1225,7 @@ nsGrid::GetScrollBox(nsIFrame* aChild)
|
||||
return nullptr;
|
||||
|
||||
// get parent
|
||||
nsIFrame* parent = nsBox::GetParentBox(aChild);
|
||||
nsIFrame* parent = nsBox::GetParentXULBox(aChild);
|
||||
|
||||
// walk up until we find a scrollframe or a part
|
||||
// if it's a scrollframe return it.
|
||||
@@ -1242,7 +1242,7 @@ nsGrid::GetScrollBox(nsIFrame* aChild)
|
||||
if (parentGridRow)
|
||||
break;
|
||||
|
||||
parent = nsBox::GetParentBox(parent);
|
||||
parent = nsBox::GetParentXULBox(parent);
|
||||
}
|
||||
|
||||
return aChild;
|
||||
|
||||
@@ -27,7 +27,7 @@ nsGridCell::~nsGridCell()
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridCell::GetPrefSize(nsBoxLayoutState& aState)
|
||||
nsGridCell::GetXULPrefSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize sum(0,0);
|
||||
|
||||
@@ -36,7 +36,7 @@ nsGridCell::GetPrefSize(nsBoxLayoutState& aState)
|
||||
// we are tall as the tallest child plus its top offset
|
||||
|
||||
if (mBoxInColumn) {
|
||||
nsSize pref = mBoxInColumn->GetPrefSize(aState);
|
||||
nsSize pref = mBoxInColumn->GetXULPrefSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInColumn, pref);
|
||||
nsGridLayout2::AddOffset(mBoxInColumn, pref);
|
||||
@@ -45,7 +45,7 @@ nsGridCell::GetPrefSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
if (mBoxInRow) {
|
||||
nsSize pref = mBoxInRow->GetPrefSize(aState);
|
||||
nsSize pref = mBoxInRow->GetXULPrefSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInRow, pref);
|
||||
nsGridLayout2::AddOffset(mBoxInRow, pref);
|
||||
@@ -57,7 +57,7 @@ nsGridCell::GetPrefSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridCell::GetMinSize(nsBoxLayoutState& aState)
|
||||
nsGridCell::GetXULMinSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize sum(0, 0);
|
||||
|
||||
@@ -66,7 +66,7 @@ nsGridCell::GetMinSize(nsBoxLayoutState& aState)
|
||||
// we are tall as the tallest child plus its top offset
|
||||
|
||||
if (mBoxInColumn) {
|
||||
nsSize min = mBoxInColumn->GetMinSize(aState);
|
||||
nsSize min = mBoxInColumn->GetXULMinSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInColumn, min);
|
||||
nsGridLayout2::AddOffset(mBoxInColumn, min);
|
||||
@@ -75,7 +75,7 @@ nsGridCell::GetMinSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
if (mBoxInRow) {
|
||||
nsSize min = mBoxInRow->GetMinSize(aState);
|
||||
nsSize min = mBoxInRow->GetXULMinSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInRow, min);
|
||||
nsGridLayout2::AddOffset(mBoxInRow, min);
|
||||
@@ -87,7 +87,7 @@ nsGridCell::GetMinSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridCell::GetMaxSize(nsBoxLayoutState& aState)
|
||||
nsGridCell::GetXULMaxSize(nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize sum(NS_INTRINSICSIZE, NS_INTRINSICSIZE);
|
||||
|
||||
@@ -96,7 +96,7 @@ nsGridCell::GetMaxSize(nsBoxLayoutState& aState)
|
||||
// we are tall as the shortest child plus its top offset
|
||||
|
||||
if (mBoxInColumn) {
|
||||
nsSize max = mBoxInColumn->GetMaxSize(aState);
|
||||
nsSize max = mBoxInColumn->GetXULMaxSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInColumn, max);
|
||||
nsGridLayout2::AddOffset(mBoxInColumn, max);
|
||||
@@ -105,7 +105,7 @@ nsGridCell::GetMaxSize(nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
if (mBoxInRow) {
|
||||
nsSize max = mBoxInRow->GetMaxSize(aState);
|
||||
nsSize max = mBoxInRow->GetXULMaxSize(aState);
|
||||
|
||||
nsBox::AddMargin(mBoxInRow, max);
|
||||
nsGridLayout2::AddOffset(mBoxInRow, max);
|
||||
@@ -118,10 +118,10 @@ nsGridCell::GetMaxSize(nsBoxLayoutState& aState)
|
||||
|
||||
|
||||
bool
|
||||
nsGridCell::IsCollapsed()
|
||||
nsGridCell::IsXULCollapsed()
|
||||
{
|
||||
return ((mBoxInColumn && mBoxInColumn->IsCollapsed()) ||
|
||||
(mBoxInRow && mBoxInRow->IsCollapsed()));
|
||||
return ((mBoxInColumn && mBoxInColumn->IsXULCollapsed()) ||
|
||||
(mBoxInRow && mBoxInRow->IsXULCollapsed()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ public:
|
||||
nsGridCell();
|
||||
~nsGridCell();
|
||||
|
||||
nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
bool IsCollapsed();
|
||||
nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
nsSize GetXULMaxSize(nsBoxLayoutState& aBoxLayoutState);
|
||||
bool IsXULCollapsed();
|
||||
|
||||
// accessors
|
||||
nsIFrame* GetBoxInColumn() { return mBoxInColumn; }
|
||||
|
||||
@@ -47,13 +47,13 @@ nsGridLayout2::AddOffset(nsIFrame* aChild, nsSize& aSize)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGridLayout2::Layout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
|
||||
nsGridLayout2::XULLayout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState)
|
||||
{
|
||||
// XXX This should be set a better way!
|
||||
mGrid.SetBox(aBox);
|
||||
NS_ASSERTION(aBox->GetLayoutManager() == this, "setting incorrect box");
|
||||
NS_ASSERTION(aBox->GetXULLayoutManager() == this, "setting incorrect box");
|
||||
|
||||
nsresult rv = nsStackLayout::Layout(aBox, aBoxLayoutState);
|
||||
nsresult rv = nsStackLayout::XULLayout(aBox, aBoxLayoutState);
|
||||
#ifdef DEBUG_grid
|
||||
mGrid.PrintCellMap();
|
||||
#endif
|
||||
@@ -75,7 +75,7 @@ nsGridLayout2::GetGrid(nsIFrame* aBox, int32_t* aIndex, nsGridRowLayout* aReques
|
||||
{
|
||||
// XXX This should be set a better way!
|
||||
mGrid.SetBox(aBox);
|
||||
NS_ASSERTION(aBox->GetLayoutManager() == this, "setting incorrect box");
|
||||
NS_ASSERTION(aBox->GetXULLayoutManager() == this, "setting incorrect box");
|
||||
return &mGrid;
|
||||
}
|
||||
|
||||
@@ -93,9 +93,9 @@ nsGridLayout2::AddWidth(nsSize& aSize, nscoord aSize2, bool aIsHorizontal)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridLayout2::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
nsGridLayout2::GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize minSize = nsStackLayout::GetMinSize(aBox, aState);
|
||||
nsSize minSize = nsStackLayout::GetXULMinSize(aBox, aState);
|
||||
|
||||
// if there are no <rows> tags that will sum up our columns,
|
||||
// sum up our columns here.
|
||||
@@ -132,9 +132,9 @@ nsGridLayout2::GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridLayout2::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
nsGridLayout2::GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize pref = nsStackLayout::GetPrefSize(aBox, aState);
|
||||
nsSize pref = nsStackLayout::GetXULPrefSize(aBox, aState);
|
||||
|
||||
// if there are no <rows> tags that will sum up our columns,
|
||||
// sum up our columns here.
|
||||
@@ -171,9 +171,9 @@ nsGridLayout2::GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
}
|
||||
|
||||
nsSize
|
||||
nsGridLayout2::GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
nsGridLayout2::GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aState)
|
||||
{
|
||||
nsSize maxSize = nsStackLayout::GetMaxSize(aBox, aState);
|
||||
nsSize maxSize = nsStackLayout::GetXULMaxSize(aBox, aState);
|
||||
|
||||
// if there are no <rows> tags that will sum up our columns,
|
||||
// sum up our columns here.
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD Layout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
NS_IMETHOD XULLayout(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual void IntrinsicISizesDirty(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
|
||||
virtual nsGridRowGroupLayout* CastToRowGroupLayout() override { return nullptr; }
|
||||
@@ -39,9 +39,9 @@ public:
|
||||
virtual nsIGridPart* GetParentGridPart(nsIFrame* aBox, nsIFrame** aParentBox) override {
|
||||
NS_NOTREACHED("Should not be called"); return nullptr;
|
||||
}
|
||||
virtual nsSize GetMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMinSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULMaxSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual nsSize GetXULPrefSize(nsIFrame* aBox, nsBoxLayoutState& aBoxLayoutState) override;
|
||||
virtual void CountRowsColumns(nsIFrame* aBox, int32_t& aRowCount, int32_t& aComputedColumnCount) override { aRowCount++; }
|
||||
virtual void DirtyRows(nsIFrame* aBox, nsBoxLayoutState& aState) override { }
|
||||
virtual int32_t BuildRows(nsIFrame* aBox, nsGridRow* aRows) override;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user