From 2265e713ffae9a86970052af2de90604850df3d3 Mon Sep 17 00:00:00 2001 From: Jonas Jenwald Date: Thu, 25 Oct 2018 15:52:02 +0200 Subject: [PATCH 01/26] Bug 1365105 - Clear all find highlights, in the PDF Viewer, when the findbar is closed. r=bdahl,paolo In order to support this, a new "findbarclose" event (mirroring the pre-existing "findbaropen" one) was added to the `MozFindbar.close` method in the findbar.js file. --- .../test/general/browser_findbarClose.js | 3 ++ .../pdfjs/content/PdfjsChromeUtils.jsm | 34 +++++++++++-------- toolkit/content/widgets/findbar.js | 4 +++ 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/browser/base/content/test/general/browser_findbarClose.js b/browser/base/content/test/general/browser_findbarClose.js index c48952020335..5fa6ac82026d 100644 --- a/browser/base/content/test/general/browser_findbarClose.js +++ b/browser/base/content/test/general/browser_findbarClose.js @@ -27,7 +27,10 @@ add_task(async function findbar_test() { ok(!gFindBar.hidden, "the Find bar isn't hidden after the location of a " + "subdocument changes"); + let findBarClosePromise = promiseWaitForEvent(gBrowser, "findbarclose"); gFindBar.close(); + await findBarClosePromise; + gBrowser.removeTab(newTab); }); diff --git a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm index 4c39a1c7646f..85f0f4c00bfd 100644 --- a/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm +++ b/browser/extensions/pdfjs/content/PdfjsChromeUtils.jsm @@ -192,24 +192,27 @@ var PdfjsChromeUtils = { }, handleEvent(aEvent) { + const type = aEvent.type; // Handle the tab find initialized event specially: - if (aEvent.type == "TabFindInitialized") { + if (type == "TabFindInitialized") { let browser = aEvent.target.linkedBrowser; this._hookupEventListeners(browser); - aEvent.target.removeEventListener(aEvent.type, this); + aEvent.target.removeEventListener(type, this); return; } // To avoid forwarding the message as a CPOW, create a structured cloneable // version of the event for both performance, and ease of usage, reasons. - let type = aEvent.type; - let detail = { - query: aEvent.detail.query, - caseSensitive: aEvent.detail.caseSensitive, - entireWord: aEvent.detail.entireWord, - highlightAll: aEvent.detail.highlightAll, - findPrevious: aEvent.detail.findPrevious, - }; + let detail = null; + if (type !== "findbarclose") { + detail = { + query: aEvent.detail.query, + caseSensitive: aEvent.detail.caseSensitive, + entireWord: aEvent.detail.entireWord, + highlightAll: aEvent.detail.highlightAll, + findPrevious: aEvent.detail.findPrevious, + }; + } let browser = aEvent.currentTarget.browser; if (!this._browsers.has(browser)) { @@ -222,10 +225,13 @@ var PdfjsChromeUtils = { aEvent.preventDefault(); }, - _types: ["find", - "findagain", - "findhighlightallchange", - "findcasesensitivitychange"], + _types: [ + "find", + "findagain", + "findhighlightallchange", + "findcasesensitivitychange", + "findbarclose", + ], _addEventListener(aMsg) { let browser = aMsg.target; diff --git a/toolkit/content/widgets/findbar.js b/toolkit/content/widgets/findbar.js index 6270e844fc1f..0a744b26a158 100644 --- a/toolkit/content/widgets/findbar.js +++ b/toolkit/content/widgets/findbar.js @@ -668,6 +668,10 @@ class MozFindbar extends XULElement { this.setAttribute("noanim", true); this.hidden = true; + let event = document.createEvent("Events"); + event.initEvent("findbarclose", true, false); + this.dispatchEvent(event); + // 'focusContent()' iterates over all listeners in the chrome // process, so we need to call it from here. this.browser.finder.focusContent(); From a4dfaf285f2dcb056a5849108d3359b2f8fd8497 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sat, 20 Oct 2018 09:22:11 -0600 Subject: [PATCH 02/26] Bug 1488453 - Use release mode assertions in HashTable, r=mccr8. --HG-- extra : rebase_source : 95945068c173777a422f459ad46af91f3889d7cd --- toolkit/recordreplay/HashTable.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/toolkit/recordreplay/HashTable.cpp b/toolkit/recordreplay/HashTable.cpp index 2305ee7b7841..692828e05f75 100644 --- a/toolkit/recordreplay/HashTable.cpp +++ b/toolkit/recordreplay/HashTable.cpp @@ -87,7 +87,7 @@ class StableHashTableInfo // Get an existing key in the table. KeyInfo* FindKeyInfo(HashNumber aOriginalHash, const void* aKey, HashInfo** aHashInfo = nullptr) { HashToKeyMap::iterator iter = mHashToKey.find(aOriginalHash); - MOZ_ASSERT(iter != mHashToKey.end()); + MOZ_RELEASE_ASSERT(iter != mHashToKey.end()); HashInfo* hashInfo = iter->second.get(); for (KeyInfo& keyInfo : hashInfo->mKeys) { @@ -114,7 +114,7 @@ public: } ~StableHashTableInfo() { - MOZ_ASSERT(mHashToKey.empty()); + MOZ_RELEASE_ASSERT(mHashToKey.empty()); DeallocateMemory(mCallbackStorage, CallbackStorageCapacity, MemoryKind::Tracked); } @@ -175,7 +175,7 @@ public: HashNumber GetOriginalHashNumber(const void* aKey) { KeyToHashMap::iterator iter = mKeyToHash.find(aKey); - MOZ_ASSERT(iter != mKeyToHash.end()); + MOZ_RELEASE_ASSERT(iter != mKeyToHash.end()); return iter->second; } @@ -212,7 +212,7 @@ public: } HashNumber GetLastNewHash(const void* aKey) { - MOZ_ASSERT(aKey == mLastKey); + MOZ_RELEASE_ASSERT(aKey == mLastKey); return mLastNewHash; } @@ -302,7 +302,7 @@ WrapPLHashAllocEntry(void* aAllocPrivate, const void* aKey) // the hashes are supplied directly to the table and we don't have a chance // to modify them. Fortunately, none of these tables are iterated in a way // that can cause the replay to diverge, so just punt in these cases. - MOZ_ASSERT(info->IsEmpty()); + MOZ_RELEASE_ASSERT(info->IsEmpty()); } return info->mAllocOps From d59167832b9fb4b6e2d5ffd16c249254ce30b451 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sat, 20 Oct 2018 09:23:36 -0600 Subject: [PATCH 03/26] Bug 1500690 - Relax compositor thread ID assertion, r=nical. --HG-- extra : rebase_source : 8a45cb4265fd27ec20d56610398005ce849e1126 --- toolkit/recordreplay/ipc/ChildIPC.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/toolkit/recordreplay/ipc/ChildIPC.cpp b/toolkit/recordreplay/ipc/ChildIPC.cpp index b1c3e73b740e..0316961d6fba 100644 --- a/toolkit/recordreplay/ipc/ChildIPC.cpp +++ b/toolkit/recordreplay/ipc/ChildIPC.cpp @@ -545,7 +545,7 @@ PaintFromMainThread() void NotifyPaintComplete() { - MOZ_RELEASE_ASSERT(Thread::Current()->Id() == gCompositorThreadId); + MOZ_RELEASE_ASSERT(!gCompositorThreadId || Thread::Current()->Id() == gCompositorThreadId); // Notify the main thread in case it is waiting for this paint to complete. { From 0ceed43834366703a353050f4e7221dd98e7d88d Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sat, 20 Oct 2018 10:41:21 -0600 Subject: [PATCH 04/26] Bug 1500697 - Redirect SCDynamicStore APIs, r=mccr8. --HG-- extra : rebase_source : 16212915fc4f519cc851adca66a1c75449084395 --- toolkit/recordreplay/ProcessRedirectDarwin.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/toolkit/recordreplay/ProcessRedirectDarwin.cpp b/toolkit/recordreplay/ProcessRedirectDarwin.cpp index 8d3be45f1aa6..f63c01c94d46 100644 --- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp +++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp @@ -291,6 +291,7 @@ namespace recordreplay { MACRO(CFRunLoopGetCurrent, RR_ScalarRval) \ MACRO(CFRunLoopRemoveSource) \ MACRO(CFRunLoopSourceCreate, RR_ScalarRval, Preamble_CFRunLoopSourceCreate) \ + MACRO(CFRunLoopSourceInvalidate) \ MACRO(CFRunLoopSourceSignal) \ MACRO(CFRunLoopWakeUp) \ MACRO(CFStringAppendCharacters) \ @@ -589,6 +590,11 @@ namespace recordreplay { MACRO(ReleaseEvent, RR_ScalarRval) \ MACRO(RemoveEventFromQueue, RR_ScalarRval) \ MACRO(RetainEvent, RR_ScalarRval) \ + MACRO(SCDynamicStoreCopyProxies, RR_ScalarRval) \ + MACRO(SCDynamicStoreCreate, RR_ScalarRval) \ + MACRO(SCDynamicStoreCreateRunLoopSource, RR_ScalarRval) \ + MACRO(SCDynamicStoreKeyCreateProxies, RR_ScalarRval) \ + MACRO(SCDynamicStoreSetNotificationKeys, RR_ScalarRval) \ MACRO(SendEventToEventTarget, RR_ScalarRval) \ /* These are not public APIs, but other redirected functions may be aliases for */ \ /* these which are dynamically installed on the first call in a way that our */ \ From 274519d9f89e993367db6bcbbd7f34cbe8455951 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:01:54 -0600 Subject: [PATCH 05/26] Bug 1500805 Part 1 - Allow idle threads to be selectively resumed, r=mccr8. --HG-- extra : rebase_source : a29ef7316aea2ce566023349639f489ff7b0d9b5 --- toolkit/recordreplay/Thread.cpp | 39 +++++++++++++-------------------- toolkit/recordreplay/Thread.h | 10 +++++++++ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/toolkit/recordreplay/Thread.cpp b/toolkit/recordreplay/Thread.cpp index 21f9aadcd85f..efffd4d44702 100644 --- a/toolkit/recordreplay/Thread.cpp +++ b/toolkit/recordreplay/Thread.cpp @@ -364,24 +364,16 @@ RecordReplayInterface_InternalAreThreadEventsDisallowed() // Thread Coordination /////////////////////////////////////////////////////////////////////////////// -// Whether all threads should attempt to idle. -static Atomic gThreadsShouldIdle; - -// Whether all threads are considered to be idle. -static Atomic gThreadsAreIdle; - /* static */ void Thread::WaitForIdleThreads() { MOZ_RELEASE_ASSERT(CurrentIsMainThread()); - MOZ_RELEASE_ASSERT(!gThreadsShouldIdle); - MOZ_RELEASE_ASSERT(!gThreadsAreIdle); - gThreadsShouldIdle = true; - MonitorAutoLock lock(*gMonitor); for (size_t i = MainThreadId + 1; i <= MaxRecordedThreadId; i++) { - GetById(i)->mUnrecordedWaitNotified = false; + Thread* thread = GetById(i); + thread->mShouldIdle = true; + thread->mUnrecordedWaitNotified = false; } while (true) { bool done = true; @@ -426,23 +418,21 @@ Thread::WaitForIdleThreads() MonitorAutoUnlock unlock(*gMonitor); WaitNoIdle(); } +} - gThreadsAreIdle = true; +/* static */ void +Thread::ResumeSingleIdleThread(size_t aId) +{ + GetById(aId)->mShouldIdle = false; + Notify(aId); } /* static */ void Thread::ResumeIdleThreads() { MOZ_RELEASE_ASSERT(CurrentIsMainThread()); - - MOZ_RELEASE_ASSERT(gThreadsAreIdle); - gThreadsAreIdle = false; - - MOZ_RELEASE_ASSERT(gThreadsShouldIdle); - gThreadsShouldIdle = false; - for (size_t i = MainThreadId + 1; i <= MaxRecordedThreadId; i++) { - Notify(i); + ResumeSingleIdleThread(i); } } @@ -464,7 +454,7 @@ Thread::NotifyUnrecordedWait(const std::function& aCallback, bool aOnlyW // The main thread might be able to make progress now by calling the routine // if it is waiting for idle replay threads. - if (gThreadsShouldIdle) { + if (mShouldIdle) { Notify(MainThreadId); } } @@ -473,7 +463,8 @@ Thread::NotifyUnrecordedWait(const std::function& aCallback, bool aOnlyW Thread::MaybeWaitForCheckpointSave() { MonitorAutoLock lock(*gMonitor); - while (gThreadsShouldIdle) { + Thread* thread = Thread::Current(); + while (thread->mShouldIdle) { MonitorAutoUnlock unlock(*gMonitor); Wait(); } @@ -531,7 +522,7 @@ Thread::Wait() } thread->mIdle = true; - if (gThreadsShouldIdle) { + if (thread->mShouldIdle) { // Notify the main thread that we just became idle. Notify(MainThreadId); } @@ -546,7 +537,7 @@ Thread::Wait() RestoreThreadStack(thread->Id()); Unreachable(); } - } while (gThreadsShouldIdle); + } while (thread->mShouldIdle); thread->mIdle = false; thread->SetPassThrough(false); diff --git a/toolkit/recordreplay/Thread.h b/toolkit/recordreplay/Thread.h index 569a18036483..ac0984f85662 100644 --- a/toolkit/recordreplay/Thread.h +++ b/toolkit/recordreplay/Thread.h @@ -127,6 +127,9 @@ private: // File descriptor to notify to wake the thread up, fixed at creation. FileHandle mNotifyfd; + // Whether the thread should attempt to idle. + Atomic mShouldIdle; + // Whether the thread is waiting on idlefd. Atomic mIdle; @@ -289,6 +292,13 @@ public: // After WaitForIdleThreads(), the main thread will call this to allow // other threads to resume execution. static void ResumeIdleThreads(); + + // Allow a single thread to resume execution. + static void ResumeSingleIdleThread(size_t aId); + + // Return whether this thread is in the idle state entered after + // WaitForIdleThreads. + bool IsIdle() { return mIdle; } }; // This uses a stack pointer instead of TLS to make sure events are passed From f804910b8601f54643b849da3c0390fb802eeac0 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:02:32 -0600 Subject: [PATCH 06/26] Bug 1500805 Part 2 - Ensure non-main threads are idle when diverging from the recording, r=mccr8. --HG-- extra : rebase_source : 0d9e1ae7f0bcda2631781cc4b4a73cee88e886c8 --- toolkit/recordreplay/ProcessRewind.cpp | 5 +++++ toolkit/recordreplay/ipc/ChildIPC.cpp | 23 +++++++++++------------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/toolkit/recordreplay/ProcessRewind.cpp b/toolkit/recordreplay/ProcessRewind.cpp index 91bc29ef1b0b..d0cd978b5ea3 100644 --- a/toolkit/recordreplay/ProcessRewind.cpp +++ b/toolkit/recordreplay/ProcessRewind.cpp @@ -199,6 +199,11 @@ DivergeFromRecording() // Reset middleman call state whenever we first diverge from the recording. child::SendResetMiddlemanCalls(); + // Make sure all non-main threads are idle before we begin diverging. This + // thread's new behavior can change values used by other threads and induce + // recording mismatches. + Thread::WaitForIdleThreads(); + thread->DivergeFromRecording(); } diff --git a/toolkit/recordreplay/ipc/ChildIPC.cpp b/toolkit/recordreplay/ipc/ChildIPC.cpp index 0316961d6fba..0efa27599731 100644 --- a/toolkit/recordreplay/ipc/ChildIPC.cpp +++ b/toolkit/recordreplay/ipc/ChildIPC.cpp @@ -577,22 +577,21 @@ Repaint(size_t* aWidth, size_t* aHeight) // and the last graphics we sent will still be correct. Thread* compositorThread = Thread::GetById(gCompositorThreadId); if (!compositorThread->WillDivergeFromRecordingSoon()) { + // Allow the compositor to diverge from the recording so it can perform + // any paint we are about to trigger, or finish any in flight paint that + // that existed at the point we are paused at. + Thread::GetById(gCompositorThreadId)->SetShouldDivergeFromRecording(); + Thread::ResumeSingleIdleThread(gCompositorThreadId); + // Create an artifical vsync to see if graphics have changed since the last // paint and a new paint is needed. NotifyVsyncObserver(); - if (gNumPendingPaints) { - // Allow the compositor to diverge from the recording so it can perform - // any paint we just triggered, or finish any in flight paint that that - // existed at the point we are paused at. - Thread::GetById(gCompositorThreadId)->SetShouldDivergeFromRecording(); - - // Wait for the compositor to finish all in flight paints, including any - // one we just triggered. - MonitorAutoLock lock(*gMonitor); - while (gNumPendingPaints) { - gMonitor->Wait(); - } + // Wait for the compositor to finish all in flight paints, including any + // one we just triggered. + MonitorAutoLock lock(*gMonitor); + while (gNumPendingPaints) { + gMonitor->Wait(); } } From cb7d3c281c1cbfc2793aabd398d6bd4ef34b4d91 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:03:34 -0600 Subject: [PATCH 07/26] Bug 1500805 Part 3 - Rewind instead of deadlocking when taking a lock held by an idle thread, r=mccr8. --HG-- extra : rebase_source : 6d3dd61782990d5a80d0469f44cd5801faa1d6d1 --- toolkit/recordreplay/Lock.cpp | 20 ++++++++++++++++++-- toolkit/recordreplay/Lock.h | 5 ++++- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/toolkit/recordreplay/Lock.cpp b/toolkit/recordreplay/Lock.cpp index 85a236d0939e..da567fc82852 100644 --- a/toolkit/recordreplay/Lock.cpp +++ b/toolkit/recordreplay/Lock.cpp @@ -135,10 +135,21 @@ Lock::Find(void* aNativeLock) // should be generated right now. Doing things in this order avoids // reentrancy issues when initializing the thread-local state used by // these calls. - if (AreThreadEventsPassedThrough() || HasDivergedFromRecording()) { + Lock* lock = iter->second; + if (AreThreadEventsPassedThrough()) { return nullptr; } - return iter->second; + if (HasDivergedFromRecording()) { + // When diverged from the recording, don't allow uses of locks that are + // held by idling threads that have not diverged from the recording. + // This will cause the process to deadlock, so rewind instead. + if (lock->mOwner && Thread::GetById(lock->mOwner)->IsIdle()) { + EnsureNotDivergedFromRecording(); + Unreachable(); + } + return nullptr; + } + return lock; } } @@ -171,6 +182,9 @@ Lock::Enter() while (thread->Id() != acquires->mNextOwner && !thread->MaybeDivergeFromRecording()) { Thread::Wait(); } + if (!thread->HasDivergedFromRecording()) { + mOwner = thread->Id(); + } } } @@ -179,6 +193,8 @@ Lock::Exit() { Thread* thread = Thread::Current(); if (IsReplaying() && !thread->HasDivergedFromRecording()) { + mOwner = 0; + // Notify the next owner before releasing the lock. LockAcquires* acquires = gLockAcquires.Get(mId); acquires->ReadAndNotifyNextOwner(thread); diff --git a/toolkit/recordreplay/Lock.h b/toolkit/recordreplay/Lock.h index 3afe03c03027..db70cb0ca507 100644 --- a/toolkit/recordreplay/Lock.h +++ b/toolkit/recordreplay/Lock.h @@ -30,9 +30,12 @@ class Lock // Unique ID for this lock. size_t mId; + // When replaying, any thread owning this lock as part of the recording. + Atomic mOwner; + public: explicit Lock(size_t aId) - : mId(aId) + : mId(aId), mOwner(0) { MOZ_ASSERT(aId); } From 650805afa6f0f1b25ffb63d83c2a1931f3bbed9e Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:04:18 -0600 Subject: [PATCH 08/26] Bug 1500805 Part 4 - Watch for bogus pointers when checking for constant compile time strings, r=mccr8. --HG-- extra : rebase_source : 7517295161e729dabdeae940b8ba4569df8f7754 --- toolkit/recordreplay/MemorySnapshot.cpp | 11 ++++ toolkit/recordreplay/MemorySnapshot.h | 5 ++ .../recordreplay/ProcessRedirectDarwin.cpp | 55 +++++++++---------- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/toolkit/recordreplay/MemorySnapshot.cpp b/toolkit/recordreplay/MemorySnapshot.cpp index 9eb14dc4dc1e..a8dc49d7a56e 100644 --- a/toolkit/recordreplay/MemorySnapshot.cpp +++ b/toolkit/recordreplay/MemorySnapshot.cpp @@ -662,6 +662,17 @@ HandleDirtyMemoryFault(uint8_t* aAddress) return true; } +bool +MemoryRangeIsTracked(void* aAddress, size_t aSize) +{ + for (uint8_t* ptr = PageBase(aAddress); ptr < (uint8_t*) aAddress + aSize; ptr += PageSize) { + if (!IsTrackedAddress(ptr, nullptr)) { + return false; + } + } + return true; +} + void UnrecoverableSnapshotFailure() { diff --git a/toolkit/recordreplay/MemorySnapshot.h b/toolkit/recordreplay/MemorySnapshot.h index 0ffdb65d76f8..f44adf05d96b 100644 --- a/toolkit/recordreplay/MemorySnapshot.h +++ b/toolkit/recordreplay/MemorySnapshot.h @@ -50,6 +50,11 @@ void RegisterAllocatedMemory(void* aBaseAddress, size_t aSize, MemoryKind aKind) // been reached. void AddInitialUntrackedMemoryRegion(uint8_t* aBase, size_t aSize); +// Return whether a range of memory is in a tracked region. This excludes +// memory that was allocated after the last checkpoint and is not write +// protected. +bool MemoryRangeIsTracked(void* aAddress, size_t aSize); + // Initialize the memory snapshots system. void InitializeMemorySnapshots(); diff --git a/toolkit/recordreplay/ProcessRedirectDarwin.cpp b/toolkit/recordreplay/ProcessRedirectDarwin.cpp index f63c01c94d46..c7d4ce79c9bb 100644 --- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp +++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp @@ -695,20 +695,6 @@ ReplayInvokeCallback(size_t aCallbackId) // Middleman Call Helpers /////////////////////////////////////////////////////////////////////////////// -static bool -TestObjCObjectClass(id aObj, const char* aName) -{ - Class cls = object_getClass(aObj); - while (cls) { - const char* className = class_getName(cls); - if (!strcmp(className, aName)) { - return true; - } - cls = class_getSuperclass(cls); - } - return false; -} - // Inputs that originate from static data in the replaying process itself // rather than from previous middleman calls. enum class ObjCInputKind { @@ -716,6 +702,14 @@ enum class ObjCInputKind { ConstantString, }; +// Internal layout of a constant compile time CFStringRef. +struct CFConstantString { + Class mClass; + size_t mStuff; + char* mData; + size_t mLength; +}; + // Capture an Objective C or CoreFoundation input to a call, which may come // either from another middleman call, or from static data in the replaying // process. @@ -759,22 +753,23 @@ Middleman_ObjCInput(MiddlemanCallContext& aCx, id* aThingPtr) } // Watch for constant compile time strings baked into the generated code or - // stored in system libraries. We can crash here if the object came from - // e.g. a replayed pointer from the recording, as can happen if not enough - // redirections have middleman call hooks. We could do better here to make - // sure the pointer looks like it could be a constant string, but it seems - // better and simpler to crash more reliably here than mask problems due to - // missing middleman call hooks. - if (TestObjCObjectClass(*aThingPtr, "NSString")) { - AutoPassThroughThreadEvents pt; - CFIndex len = CFStringGetLength((CFStringRef)*aThingPtr); - InfallibleVector buffer; - buffer.appendN(0, len); - CFStringGetCharacters((CFStringRef)*aThingPtr, { 0, len }, buffer.begin()); - aCx.WriteInputScalar((size_t) ObjCInputKind::ConstantString); - aCx.WriteInputScalar(len); - aCx.WriteInputBytes(buffer.begin(), len * sizeof(UniChar)); - return; + // stored in system libraries. Be careful when accessing the pointer as in + // the case where a middleman call hook for a function is missing the + // pointer could have originated from the recording and its address may not + // be mapped. In this case we would rather gracefully recover and fail to + // paint, instead of crashing. + if (MemoryRangeIsTracked(*aThingPtr, sizeof(CFConstantString))) { + CFConstantString* str = (CFConstantString*) *aThingPtr; + if (str->mClass == objc_lookUpClass("__NSCFConstantString") && + str->mLength <= 4096 && // Sanity check. + MemoryRangeIsTracked(str->mData, str->mLength)) { + InfallibleVector buffer; + NS_ConvertUTF8toUTF16 converted(str->mData, str->mLength); + aCx.WriteInputScalar((size_t) ObjCInputKind::ConstantString); + aCx.WriteInputScalar(str->mLength); + aCx.WriteInputBytes(converted.get(), str->mLength * sizeof(UniChar)); + return; + } } aCx.MarkAsFailed(); From d03d8f7b0bdc2eb92c1d68c357f7aa1d81a8f0b7 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:05:00 -0600 Subject: [PATCH 09/26] Bug 1500805 Part 5 - Fix handling when creating threads after diverging from the recording, r=mccr8. --HG-- extra : rebase_source : 1d1f02c7a07e25a4219b145deffae7b44217c6da --- toolkit/recordreplay/ProcessRedirectDarwin.cpp | 8 +++++++- toolkit/recordreplay/Thread.cpp | 3 +-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/toolkit/recordreplay/ProcessRedirectDarwin.cpp b/toolkit/recordreplay/ProcessRedirectDarwin.cpp index c7d4ce79c9bb..30ed612c4157 100644 --- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp +++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp @@ -152,7 +152,7 @@ namespace recordreplay { MACRO(pthread_cond_wait, nullptr, Preamble_pthread_cond_wait) \ MACRO(pthread_cond_timedwait, nullptr, Preamble_pthread_cond_timedwait) \ MACRO(pthread_cond_timedwait_relative_np, nullptr, Preamble_pthread_cond_timedwait_relative_np) \ - MACRO(pthread_create, nullptr, Preamble_pthread_create, nullptr, Preamble_SetError) \ + MACRO(pthread_create, nullptr, Preamble_pthread_create) \ MACRO(pthread_join, nullptr, Preamble_pthread_join) \ MACRO(pthread_mutex_init, nullptr, Preamble_pthread_mutex_init) \ MACRO(pthread_mutex_destroy, nullptr, Preamble_pthread_mutex_destroy) \ @@ -1213,6 +1213,12 @@ Preamble_pthread_create(CallArguments* aArguments) *token = Thread::StartThread((Thread::Callback) start, startArg, detachState == PTHREAD_CREATE_JOINABLE); + if (!*token) { + // Don't create new threads after diverging from the recording. + MOZ_RELEASE_ASSERT(HasDivergedFromRecording()); + return Preamble_SetError(aArguments); + } + aArguments->Rval() = 0; return PreambleResult::Veto; } diff --git a/toolkit/recordreplay/Thread.cpp b/toolkit/recordreplay/Thread.cpp index efffd4d44702..d07b70e58273 100644 --- a/toolkit/recordreplay/Thread.cpp +++ b/toolkit/recordreplay/Thread.cpp @@ -237,8 +237,7 @@ Thread::StartThread(Callback aStart, void* aArgument, bool aNeedsJoin) Thread* thread = Thread::Current(); RecordingEventSection res(thread); if (!res.CanAccessEvents()) { - EnsureNotDivergedFromRecording(); - Unreachable(); + return 0; } MonitorAutoLock lock(*gMonitor); From 565ba58f1b76f38a6df7ad7fc23599de01880533 Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:09:13 -0600 Subject: [PATCH 10/26] Bug 1500805 Part 6 - Add middleman call hooks for some graphics APIs, r=mccr8. --HG-- extra : rebase_source : 7ace44a7b32a0878607e53e913017a4f439b87b6 --- toolkit/recordreplay/MiddlemanCall.h | 2 +- .../recordreplay/ProcessRedirectDarwin.cpp | 54 ++++++++++++++++--- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/toolkit/recordreplay/MiddlemanCall.h b/toolkit/recordreplay/MiddlemanCall.h index b7236081b46c..d8880d02e565 100644 --- a/toolkit/recordreplay/MiddlemanCall.h +++ b/toolkit/recordreplay/MiddlemanCall.h @@ -354,7 +354,7 @@ void ResetMiddlemanCalls(); /////////////////////////////////////////////////////////////////////////////// // Capture the contents of an input buffer at BufferArg with element count at CountArg. -template +template static inline void Middleman_Buffer(MiddlemanCallContext& aCx) { diff --git a/toolkit/recordreplay/ProcessRedirectDarwin.cpp b/toolkit/recordreplay/ProcessRedirectDarwin.cpp index 30ed612c4157..0a4695c885bf 100644 --- a/toolkit/recordreplay/ProcessRedirectDarwin.cpp +++ b/toolkit/recordreplay/ProcessRedirectDarwin.cpp @@ -329,9 +329,9 @@ namespace recordreplay { MACRO(CFURLCreateWithString, RR_ScalarRval) \ MACRO(CFURLGetFileSystemRepresentation, RR_Compose>) \ MACRO(CFURLGetFSRef, RR_Compose>) \ - MACRO(CFUUIDCreate, RR_ScalarRval) \ + MACRO(CFUUIDCreate, RR_ScalarRval, nullptr, Middleman_CreateCFTypeRval) \ MACRO(CFUUIDCreateString, RR_ScalarRval) \ - MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval) \ + MACRO(CFUUIDGetUUIDBytes, RR_ComplexScalarRval, nullptr, Middleman_CFTypeArg<0>) \ MACRO(CGAffineTransformConcat, RR_OversizeRval) \ MACRO(CGBitmapContextCreateImage, RR_ScalarRval) \ MACRO(CGBitmapContextCreateWithData, \ @@ -387,8 +387,9 @@ namespace recordreplay { Middleman_StackArgumentData>) \ MACRO(CGContextScaleCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \ MACRO(CGContextTranslateCTM, nullptr, nullptr, Middleman_UpdateCFTypeArg<0>) \ - MACRO(CGDataProviderCreateWithData, RR_Compose) \ - MACRO(CGDataProviderRelease) \ + MACRO(CGDataProviderCreateWithData, RR_Compose, \ + nullptr, Middleman_CGDataProviderCreateWithData) \ + MACRO(CGDataProviderRelease, nullptr, nullptr, nullptr, Preamble_Veto<0>) \ MACRO(CGDisplayCopyColorSpace, RR_ScalarRval) \ MACRO(CGDisplayIOServicePort, RR_ScalarRval) \ MACRO(CGEventSourceCounterForEventType, RR_ScalarRval) \ @@ -399,7 +400,8 @@ namespace recordreplay { MACRO(CGFontCopyVariations, RR_ScalarRval, nullptr, \ Middleman_Compose, Middleman_CreateCFTypeRval>) \ MACRO(CGFontCreateCopyWithVariations, RR_ScalarRval) \ - MACRO(CGFontCreateWithDataProvider, RR_ScalarRval) \ + MACRO(CGFontCreateWithDataProvider, RR_ScalarRval, nullptr, \ + Middleman_Compose, Middleman_CreateCFTypeRval>) \ MACRO(CGFontCreateWithFontName, RR_ScalarRval, nullptr, \ Middleman_Compose, Middleman_CreateCFTypeRval>) \ MACRO(CGFontCreateWithPlatformFont, RR_ScalarRval) \ @@ -443,10 +445,14 @@ namespace recordreplay { Middleman_Compose, Middleman_CreateCFTypeRval>) \ MACRO(CTFontCopyTable, RR_ScalarRval, nullptr, \ Middleman_Compose, Middleman_CreateCFTypeRval>) \ - MACRO(CTFontCopyVariationAxes, RR_ScalarRval) \ + MACRO(CTFontCopyVariationAxes, RR_ScalarRval, nullptr, \ + Middleman_Compose, Middleman_CreateCFTypeRval>) \ MACRO(CTFontCreateForString, RR_ScalarRval, nullptr, \ Middleman_Compose, Middleman_CFTypeArg<1>, Middleman_CreateCFTypeRval>) \ - MACRO(CTFontCreatePathForGlyph, RR_ScalarRval) \ + MACRO(CTFontCreatePathForGlyph, RR_ScalarRval, nullptr, \ + Middleman_Compose, \ + Middleman_BufferFixedSize<2, sizeof(CGAffineTransform)>, \ + Middleman_CreateCFTypeRval>) \ MACRO(CTFontCreateWithFontDescriptor, RR_ScalarRval, nullptr, \ Middleman_Compose, \ Middleman_BufferFixedSize<1, sizeof(CGAffineTransform)>, \ @@ -1759,6 +1765,7 @@ Middleman_CFArrayGetValueAtIndex(MiddlemanCallContext& aCx) if (call) { switch (call->mCallId) { case CallEvent_CTLineGetGlyphRuns: + case CallEvent_CTFontCopyVariationAxes: case CallEvent_CTFontDescriptorCreateMatchingFontDescriptors: isCFTypeRval = true; break; @@ -2055,6 +2062,39 @@ RR_CGDataProviderCreateWithData(Stream& aEvents, CallArguments* aArguments, Erro } } +static void +ReleaseDataCallback(void*, const void* aData, size_t) +{ + free((void*) aData); +} + +static void +Middleman_CGDataProviderCreateWithData(MiddlemanCallContext& aCx) +{ + Middleman_Buffer<1, 2>(aCx); + Middleman_CreateCFTypeRval(aCx); + + auto& info = aCx.mArguments->Arg<0, void*>(); + auto& data = aCx.mArguments->Arg<1, const void*>(); + auto& size = aCx.mArguments->Arg<2, size_t>(); + auto& releaseData = aCx.mArguments->Arg<3, CGDataProviderReleaseDataCallback>(); + + // Make a copy of the data that won't be released the next time middleman + // calls are reset, in case CoreGraphics decides to hang onto the data + // provider after that point. + if (aCx.mPhase == MiddlemanCallPhase::MiddlemanInput) { + void* newData = malloc(size); + memcpy(newData, data, size); + data = newData; + releaseData = ReleaseDataCallback; + } + + // Immediately release the data in the replaying process. + if (aCx.mPhase == MiddlemanCallPhase::ReplayInput) { + releaseData(info, data, size); + } +} + static PreambleResult Preamble_CGPathApply(CallArguments* aArguments) { From 39ea3e05d1c7be06f971ed62c1905565586e4acc Mon Sep 17 00:00:00 2001 From: Brian Hackett Date: Sun, 21 Oct 2018 15:09:20 -0600 Subject: [PATCH 11/26] Bug 1500805 Part 7 - Avoid crashing after a middleman call returns a null value, r=mccr8. --HG-- extra : rebase_source : 4274b07437e31938349823b9229ccf3add164e9f --- toolkit/recordreplay/MiddlemanCall.cpp | 5 ++++- toolkit/recordreplay/ProcessRedirect.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/toolkit/recordreplay/MiddlemanCall.cpp b/toolkit/recordreplay/MiddlemanCall.cpp index 23bb91e01f7f..5de4a6531a3e 100644 --- a/toolkit/recordreplay/MiddlemanCall.cpp +++ b/toolkit/recordreplay/MiddlemanCall.cpp @@ -163,7 +163,7 @@ ProcessMiddlemanCall(const char* aInputData, size_t aInputSize, call->DecodeInput(inputStream); const Redirection& redirection = gRedirections[call->mCallId]; - MOZ_RELEASE_ASSERT(gRedirections[call->mCallId].mMiddlemanCall); + MOZ_RELEASE_ASSERT(redirection.mMiddlemanCall); CallArguments arguments; call->mArguments.CopyTo(&arguments); @@ -323,6 +323,9 @@ void Middleman_SystemOutput(MiddlemanCallContext& aCx, const void** aOutput, bool aUpdating) { if (!*aOutput) { + if (aCx.mPhase == MiddlemanCallPhase::MiddlemanOutput) { + aCx.mCall->SetMiddlemanValue(*aOutput); + } return; } diff --git a/toolkit/recordreplay/ProcessRedirect.cpp b/toolkit/recordreplay/ProcessRedirect.cpp index 8a1669d7640e..8d27457efb3a 100644 --- a/toolkit/recordreplay/ProcessRedirect.cpp +++ b/toolkit/recordreplay/ProcessRedirect.cpp @@ -8,6 +8,7 @@ #include "InfallibleVector.h" #include "MiddlemanCall.h" +#include "ipc/ParentInternal.h" #include "mozilla/Sprintf.h" #include @@ -99,6 +100,11 @@ RecordReplayInterceptCall(int aCallId, CallArguments* aArguments) } } + if (parent::InRepaintStressMode()) { + // We're about to crash, so print out the name of the call that failed. + Print("Could not perform middleman call: %s\n", redirection.mName); + } + // Calling any redirection which performs the standard steps will cause // debugger operations that have diverged from the recording to fail. EnsureNotDivergedFromRecording(); From 7059a8ac77b35f4572e4a3cea97f133bdc83ef8a Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Wed, 24 Oct 2018 23:40:37 -0400 Subject: [PATCH 12/26] Bug 1501910 - Pass enumerableOnly into nsIXPCScriptable::NewEnumerate, r=bzbarsky Differential Revision: https://phabricator.services.mozilla.com/D9749 --- js/xpconnect/idl/nsIXPCScriptable.idl | 3 ++- js/xpconnect/public/xpc_map_end.h | 2 +- js/xpconnect/src/XPCComponents.cpp | 5 +++++ js/xpconnect/src/XPCWrappedNativeJSOps.cpp | 3 ++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/js/xpconnect/idl/nsIXPCScriptable.idl b/js/xpconnect/idl/nsIXPCScriptable.idl index 5a0bbf12ca51..160a0dba59ef 100644 --- a/js/xpconnect/idl/nsIXPCScriptable.idl +++ b/js/xpconnect/idl/nsIXPCScriptable.idl @@ -79,7 +79,8 @@ interface nsIXPCScriptable : nsISupports boolean newEnumerate(in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, - in JSAutoIdVector properties); + in JSAutoIdVector properties, + in boolean enumerableOnly); boolean resolve(in nsIXPConnectWrappedNative wrapper, in JSContextPtr cx, in JSObjectPtr obj, in jsid id, diff --git a/js/xpconnect/public/xpc_map_end.h b/js/xpconnect/public/xpc_map_end.h index a638b9c81d8a..4fcb2ef05315 100644 --- a/js/xpconnect/public/xpc_map_end.h +++ b/js/xpconnect/public/xpc_map_end.h @@ -65,7 +65,7 @@ NS_IMETHODIMP XPC_MAP_CLASSNAME::PreCreate(nsISupports* nativeObj, JSContext * c #endif #if !((XPC_MAP_FLAGS) & XPC_SCRIPTABLE_WANT_NEWENUMERATE) -NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, JS::AutoIdVector& properties, bool* _retval) +NS_IMETHODIMP XPC_MAP_CLASSNAME::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext * cx, JSObject * obj, JS::AutoIdVector& properties, bool enumerableOnly, bool* _retval) {NS_ERROR("never called"); return NS_ERROR_NOT_IMPLEMENTED;} #endif diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index f713c1179b08..eb4bfe4b52f1 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -207,6 +207,7 @@ NS_IMETHODIMP nsXPCComponents_Interfaces::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { @@ -394,6 +395,7 @@ NS_IMETHODIMP nsXPCComponents_InterfacesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { @@ -589,6 +591,7 @@ NS_IMETHODIMP nsXPCComponents_Classes::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { nsCOMPtr compMgr; @@ -784,6 +787,7 @@ NS_IMETHODIMP nsXPCComponents_ClassesByID::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { @@ -993,6 +997,7 @@ NS_IMETHODIMP nsXPCComponents_Results::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { const char* name; diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 7caabef6f7b9..c6ec25c3fc44 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -941,7 +941,8 @@ XPC_WN_NewEnumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, } bool retval = true; - nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties, &retval); + nsresult rv = scr->NewEnumerate(wrapper, cx, obj, properties, + enumerableOnly, &retval); if (NS_FAILED(rv)) { return Throw(rv, cx); } From 84828b5af3c52a104ae6dc8e9762762bb1736e58 Mon Sep 17 00:00:00 2001 From: Nika Layzell Date: Wed, 24 Oct 2018 19:14:35 -0400 Subject: [PATCH 13/26] Bug 1501124 - Switch BackstagePass to use WebIDLGlobalNameHash, r=bzbarsky Differential Revision: https://phabricator.services.mozilla.com/D9736 --- dom/base/ContentFrameMessageManager.h | 1 - dom/base/ContentProcessMessageManager.cpp | 1 - dom/base/nsFrameMessageManager.cpp | 1 - dom/bindings/BindingUtils.cpp | 24 --- dom/bindings/Codegen.py | 179 ------------------ dom/bindings/WebIDLGlobalNameHash.cpp | 74 ++++++++ dom/bindings/WebIDLGlobalNameHash.h | 11 ++ dom/bindings/mozwebidlcodegen/__init__.py | 2 - js/xpconnect/src/XPCRuntimeService.cpp | 23 ++- js/xpconnect/src/nsXPConnect.cpp | 5 - .../lib/environments/jsm.js | 4 +- 11 files changed, 104 insertions(+), 221 deletions(-) diff --git a/dom/base/ContentFrameMessageManager.h b/dom/base/ContentFrameMessageManager.h index b4660b15a9fd..89dde8bda93e 100644 --- a/dom/base/ContentFrameMessageManager.h +++ b/dom/base/ContentFrameMessageManager.h @@ -9,7 +9,6 @@ #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/dom/MessageManagerGlobal.h" -#include "mozilla/dom/ResolveSystemBinding.h" #include "nsContentUtils.h" #include "xpcpublic.h" diff --git a/dom/base/ContentProcessMessageManager.cpp b/dom/base/ContentProcessMessageManager.cpp index 2085db19d18b..05e1a835548d 100644 --- a/dom/base/ContentProcessMessageManager.cpp +++ b/dom/base/ContentProcessMessageManager.cpp @@ -10,7 +10,6 @@ #include "mozilla/dom/ContentChild.h" #include "mozilla/dom/MessageManagerBinding.h" #include "mozilla/dom/ParentProcessMessageManager.h" -#include "mozilla/dom/ResolveSystemBinding.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ipc/SharedMap.h" diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 418087e95379..79cda17c2553 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -47,7 +47,6 @@ #include "mozilla/dom/ParentProcessMessageManager.h" #include "mozilla/dom/PermissionMessageUtils.h" #include "mozilla/dom/ProcessMessageManager.h" -#include "mozilla/dom/ResolveSystemBinding.h" #include "mozilla/dom/SameProcessMessageQueue.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ToJSValue.h" diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 01846e81e70f..8b79a0e822ac 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -56,7 +56,6 @@ #include "mozilla/dom/XULPopupElementBinding.h" #include "mozilla/dom/XULTextElementBinding.h" #include "mozilla/dom/Promise.h" -#include "mozilla/dom/ResolveSystemBinding.h" #include "mozilla/dom/WebIDLGlobalNameHash.h" #include "mozilla/dom/WorkerPrivate.h" #include "mozilla/dom/WorkerScope.h" @@ -3512,29 +3511,6 @@ UnwrapWindowProxyImpl(JSContext* cx, return NS_OK; } -bool -SystemGlobalResolve(JSContext* cx, JS::Handle obj, - JS::Handle id, bool* resolvedp) -{ - if (!ResolveGlobal(cx, obj, id, resolvedp)) { - return false; - } - - if (*resolvedp) { - return true; - } - - return ResolveSystemBinding(cx, obj, id, resolvedp); -} - -bool -SystemGlobalEnumerate(JSContext* cx, JS::Handle obj) -{ - bool ignored = false; - return JS_EnumerateStandardClasses(cx, obj) && - ResolveSystemBinding(cx, obj, JSID_VOIDHANDLE, &ignored); -} - template bool GetMaplikeSetlikeBackingObject(JSContext* aCx, JS::Handle aObj, diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 2496bd496a53..7ee6a47b6dcf 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -13576,121 +13576,6 @@ class CGRegisterWorkletBindings(CGAbstractMethod): return CGList(lines, "\n").define() -class CGSystemBindingInitIds(CGAbstractMethod): - def __init__(self): - CGAbstractMethod.__init__(self, None, 'SystemBindingInitIds', 'bool', - [Argument('JSContext*', 'aCx')]) - - def definition_body(self): - return dedent(""" - MOZ_ASSERT(NS_IsMainThread()); - - if (!idsInited) { - // We can't use range-based for because we need the index to call IdString. - for (uint32_t i = 0; i < ArrayLength(properties); ++i) { - if (!properties[i].id.init(aCx, IdString(i))) { - return false; - } - } - idsInited = true; - } - - return true; - """) - - -class CGResolveSystemBinding(CGAbstractMethod): - def __init__(self): - CGAbstractMethod.__init__(self, None, 'ResolveSystemBinding', 'bool', - [Argument('JSContext*', 'aCx'), - Argument('JS::Handle', 'aObj'), - Argument('JS::Handle', 'aId'), - Argument('bool*', 'aResolvedp')]) - - def definition_body(self): - return dedent(""" - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(idsInited); - - if (JSID_IS_VOID(aId)) { - for (const auto& property : properties) { - if (!property.enabled || property.enabled(aCx, aObj)) { - if (!property.define(aCx)) { - return false; - } - *aResolvedp = true; - } - } - return true; - } - - for (const auto& property : properties) { - if (property.id == aId) { - if (!property.enabled || property.enabled(aCx, aObj)) { - if (!property.define(aCx)) { - return false; - } - *aResolvedp = true; - break; - } - } - } - return true; - """) - - -class CGMayResolveAsSystemBindingName(CGAbstractMethod): - def __init__(self): - CGAbstractMethod.__init__(self, None, 'MayResolveAsSystemBindingName', 'bool', - [Argument('jsid', 'aId')]) - - def definition_body(self): - return dedent(""" - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(idsInited); - - for (const auto& property : properties) { - if (aId == property.id) { - return true; - } - } - return false; - """) - - -class CGGetSystemBindingNames(CGAbstractMethod): - def __init__(self): - CGAbstractMethod.__init__(self, None, 'GetSystemBindingNames', 'void', - [Argument('JSContext*', 'aCx'), - Argument('JS::Handle', 'aObj'), - Argument('JS::AutoIdVector&', 'aNames'), - Argument('bool', 'aEnumerableOnly'), - Argument('mozilla::ErrorResult&', 'aRv')]) - - def definition_body(self): - return dedent(""" - MOZ_ASSERT(NS_IsMainThread()); - - if (aEnumerableOnly) { - return; - } - - if (!SystemBindingInitIds(aCx)) { - aRv.NoteJSContextException(aCx); - return; - } - - for (const auto& property : properties) { - if (!property.enabled || property.enabled(aCx, aObj)) { - if (!aNames.append(property.id)) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - } - } - """) - - def getGlobalNames(config): names = [] for desc in config.getDescriptors(registersGlobalNamesOnWindow=True): @@ -17259,70 +17144,6 @@ class GlobalGenRoots(): # Done. return curr - @staticmethod - def ResolveSystemBinding(config): - curr = CGList([], "\n") - - descriptors = config.getDescriptors(hasInterfaceObject=True, - isExposedInWindow=True, - register=True) - properties = [desc.name for desc in descriptors] - - curr.append(CGStringTable("IdString", properties, static=True)) - - initValues = [] - for desc in descriptors: - bindingNS = toBindingNamespace(desc.name) - if desc.isExposedConditionally(): - enabled = "%s::ConstructorEnabled" % bindingNS - else: - enabled = "nullptr" - define = "%s::GetConstructorObject" % bindingNS - initValues.append("{ %s, %s },\n" % (enabled, define)) - curr.append(CGGeneric(fill(""" - struct SystemProperty - { - WebIDLGlobalNameHash::ConstructorEnabled enabled; - ProtoGetter define; - PinnedStringId id; - }; - - static SystemProperty properties[] = { - $*{init} - }; - - static bool idsInited = false; - """, - init="".join(initValues)))) - - curr.append(CGSystemBindingInitIds()) - curr.append(CGResolveSystemBinding()) - curr.append(CGMayResolveAsSystemBindingName()) - curr.append(CGGetSystemBindingNames()) - - # Wrap all of that in our namespaces. - curr = CGNamespace.build(['mozilla', 'dom'], - CGWrapper(curr, post='\n')) - curr = CGWrapper(curr, post='\n') - - # Add the includes - defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface) - for desc in config.getDescriptors(hasInterfaceObject=True, - register=True, - isExposedInWindow=True)] - defineIncludes.append("nsThreadUtils.h") # For NS_IsMainThread - defineIncludes.append("js/Id.h") # For jsid - defineIncludes.append("mozilla/dom/WebIDLGlobalNameHash.h") - - curr = CGHeaders([], [], [], [], [], defineIncludes, - 'ResolveSystemBinding', curr) - - # Add include guards. - curr = CGIncludeGuard('ResolveSystemBinding', curr) - - # Done. - return curr - @staticmethod def UnionTypes(config): unionTypes = UnionsForFile(config, None) diff --git a/dom/bindings/WebIDLGlobalNameHash.cpp b/dom/bindings/WebIDLGlobalNameHash.cpp index 0943364aee20..548e5f6e0907 100644 --- a/dom/bindings/WebIDLGlobalNameHash.cpp +++ b/dom/bindings/WebIDLGlobalNameHash.cpp @@ -206,5 +206,79 @@ WebIDLGlobalNameHash::GetNames(JSContext* aCx, JS::Handle aObj, return true; } +/* static */ +bool +WebIDLGlobalNameHash::ResolveForSystemGlobal(JSContext* aCx, + JS::Handle aObj, + JS::Handle aId, + bool* aResolvedp) +{ + MOZ_ASSERT(JS_IsGlobalObject(aObj)); + + // First we try to resolve standard classes. + if (!JS_ResolveStandardClass(aCx, aObj, aId, aResolvedp)) { + return false; + } + if (*aResolvedp) { + return true; + } + + // We don't resolve any non-string entries. + if (!JSID_IS_STRING(aId)) { + return true; + } + + // XXX(nika): In the Window case, we unwrap our global object here to handle + // XRays. I don't think we ever create xrays to system globals, so I believe + // we can skip this step. + MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(aObj), "Xrays not supported!"); + + // Look up the corresponding entry in the name table, and resolve if enabled. + const WebIDLNameTableEntry* entry = GetEntry(JSID_TO_FLAT_STRING(aId)); + if (entry && (!entry->mEnabled || entry->mEnabled(aCx, aObj))) { + if (NS_WARN_IF(!GetPerInterfaceObjectHandle(aCx, entry->mConstructorId, + entry->mCreate, + /* aDefineOnGlobal = */ true))) { + return Throw(aCx, NS_ERROR_FAILURE); + } + + *aResolvedp = true; + } + return true; +} + +/* static */ +bool +WebIDLGlobalNameHash::NewEnumerateSystemGlobal(JSContext* aCx, + JS::Handle aObj, + JS::AutoIdVector& aProperties, + bool aEnumerableOnly) +{ + MOZ_ASSERT(JS_IsGlobalObject(aObj)); + + if (!JS_NewEnumerateStandardClasses(aCx, aObj, aProperties, aEnumerableOnly)) { + return false; + } + + // All properties defined on our global are non-enumerable, so we can skip + // remaining properties. + if (aEnumerableOnly) { + return true; + } + + // Enumerate all entries & add enabled ones. + for (size_t i = 0; i < sCount; ++i) { + const WebIDLNameTableEntry& entry = sEntries[i]; + if (!entry.mEnabled || entry.mEnabled(aCx, aObj)) { + JSString* str = JS_AtomizeStringN(aCx, sNames + entry.mNameOffset, + entry.mNameLength); + if (!str || !aProperties.append(NON_INTEGER_ATOM_TO_JSID(str))) { + return false; + } + } + } + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/WebIDLGlobalNameHash.h b/dom/bindings/WebIDLGlobalNameHash.h index 58bf02a2f262..e210bb3045cd 100644 --- a/dom/bindings/WebIDLGlobalNameHash.h +++ b/dom/bindings/WebIDLGlobalNameHash.h @@ -64,6 +64,17 @@ public: NameType aNameType, JS::AutoIdVector& aNames); + // Helpers for resolving & enumerating names on the system global. + // NOTE: These are distinct as it currently lacks a ProtoAndIfaceCache, and is + // an XPCOM global. + static bool ResolveForSystemGlobal(JSContext* aCx, JS::Handle aObj, + JS::Handle aId, bool* aResolvedp); + + static bool NewEnumerateSystemGlobal(JSContext* aCx, + JS::Handle aObj, + JS::AutoIdVector& aProperties, + bool aEnumerableOnly); + private: friend struct WebIDLNameTableEntry; diff --git a/dom/bindings/mozwebidlcodegen/__init__.py b/dom/bindings/mozwebidlcodegen/__init__.py index 050ec2d829b0..5b5a72b637ce 100644 --- a/dom/bindings/mozwebidlcodegen/__init__.py +++ b/dom/bindings/mozwebidlcodegen/__init__.py @@ -134,7 +134,6 @@ class WebIDLCodegenManager(LoggingMixin): 'RegisterWorkerBindings.h', 'RegisterWorkerDebuggerBindings.h', 'RegisterWorkletBindings.h', - 'ResolveSystemBinding.h', 'UnionConversions.h', 'UnionTypes.h', } @@ -145,7 +144,6 @@ class WebIDLCodegenManager(LoggingMixin): 'RegisterWorkerBindings.cpp', 'RegisterWorkerDebuggerBindings.cpp', 'RegisterWorkletBindings.cpp', - 'ResolveSystemBinding.cpp', 'UnionTypes.cpp', 'PrototypeList.cpp', } diff --git a/js/xpconnect/src/XPCRuntimeService.cpp b/js/xpconnect/src/XPCRuntimeService.cpp index 21af20b0208a..2bce89f5ca5b 100644 --- a/js/xpconnect/src/XPCRuntimeService.cpp +++ b/js/xpconnect/src/XPCRuntimeService.cpp @@ -10,6 +10,9 @@ #include "BackstagePass.h" #include "nsIPrincipal.h" #include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/WebIDLGlobalNameHash.h" + +using namespace mozilla::dom; NS_IMPL_ISUPPORTS(BackstagePass, nsIXPCScriptable, @@ -18,11 +21,15 @@ NS_IMPL_ISUPPORTS(BackstagePass, nsIScriptObjectPrincipal, nsISupportsWeakReference) +// XXX(nika): It appears we don't have support for mayresolve hooks in +// nsIXPCScriptable, and I don't really want to add it because I'd rather just +// kill nsIXPCScriptable alltogether, so we don't use it here. + // The nsIXPCScriptable map declaration that will generate stubs for us... #define XPC_MAP_CLASSNAME BackstagePass #define XPC_MAP_QUOTED_CLASSNAME "BackstagePass" #define XPC_MAP_FLAGS (XPC_SCRIPTABLE_WANT_RESOLVE | \ - XPC_SCRIPTABLE_WANT_ENUMERATE | \ + XPC_SCRIPTABLE_WANT_NEWENUMERATE | \ XPC_SCRIPTABLE_WANT_FINALIZE | \ XPC_SCRIPTABLE_WANT_PRECREATE | \ XPC_SCRIPTABLE_USE_JSSTUB_FOR_ADDPROPERTY | \ @@ -58,17 +65,21 @@ BackstagePass::Resolve(nsIXPConnectWrappedNative* wrapper, { JS::RootedObject obj(cx, objArg); JS::RootedId id(cx, idArg); - *_retval = mozilla::dom::SystemGlobalResolve(cx, obj, id, resolvedp); + *_retval = + WebIDLGlobalNameHash::ResolveForSystemGlobal(cx, obj, id, resolvedp); return *_retval ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP -BackstagePass::Enumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, - JSObject* objArg, bool* _retval) +BackstagePass::NewEnumerate(nsIXPConnectWrappedNative* wrapper, JSContext* cx, + JSObject* objArg, JS::AutoIdVector& properties, + bool enumerableOnly, bool* _retval) { JS::RootedObject obj(cx, objArg); - *_retval = mozilla::dom::SystemGlobalEnumerate(cx, obj); - return *_retval ? NS_OK : NS_ERROR_FAILURE; + *_retval = + WebIDLGlobalNameHash::NewEnumerateSystemGlobal(cx, obj, properties, + enumerableOnly); + return *_retval ? NS_OK : NS_ERROR_FAILURE; } /***************************************************************************/ diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp index 82e5e0e72c60..dd4952175e97 100644 --- a/js/xpconnect/src/nsXPConnect.cpp +++ b/js/xpconnect/src/nsXPConnect.cpp @@ -27,7 +27,6 @@ #include "mozilla/dom/DOMPrefs.h" #include "mozilla/dom/Exceptions.h" #include "mozilla/dom/Promise.h" -#include "mozilla/dom/ResolveSystemBinding.h" #include "nsDOMMutationObserver.h" #include "nsICycleCollectorListener.h" @@ -580,10 +579,6 @@ InitClassesWithNewWrappedGlobal(JSContext* aJSContext, // we need to have a principal. MOZ_ASSERT(aPrincipal); - if (!SystemBindingInitIds(aJSContext)) { - return NS_ERROR_FAILURE; - } - InitGlobalObjectOptions(aOptions, aPrincipal); // Call into XPCWrappedNative to make a new global object, scope, and global diff --git a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js index ac1870724f64..eb2c71992866 100644 --- a/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js +++ b/tools/lint/eslint/eslint-plugin-mozilla/lib/environments/jsm.js @@ -23,8 +23,8 @@ module.exports = { "Ci": false, "Cr": false, "Cu": false, - // These globals are made available via WebIDL files, see ResolveSystemBinding in: - // https://searchfox.org/mozilla-central/source/__GENERATED__/dom/bindings/ResolveSystemBinding.cpp + // These globals are made available via WebIDL files, see WebIDLGlobalNameHash. + // XXX(nika): We should also explicitly include window-defined globals here now. "AbortController": false, "AbortSignal": false, "AddonManagerPermissions": false, From 66c9ef81880e9b832f8099ac8affc8441a5122bb Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 25 Oct 2018 16:51:44 +0200 Subject: [PATCH 14/26] Bug 1453298 - [css-text] Resolve 'text-indent' percentage against the content-box inline-size of the box itself, not its containing block. r=emilio --- layout/generic/nsLineLayout.cpp | 15 ++++----------- layout/reftests/bugs/reftest.list | 2 +- .../text-indent-parent-dynamic-ref.html | 2 +- .../text-indent-single-line-percent-ref.html | 2 +- .../text-indent-percentage-001.xht.ini | 3 --- .../text-indent-percentage-002.html.ini | 2 -- .../text-indent-percentage-003.html.ini | 6 ------ .../text-indent-percentage-004.html.ini | 2 -- .../tests/css/CSS2/css1/c547-indent-001-ref.xht | 12 ++---------- .../tests/css/CSS2/css1/c547-indent-001.xht | 2 +- .../css/CSS2/text/text-indent-percent-001-ref.xht | 4 ++-- .../reference/text-indent-percentage-001-ref.xht | 4 ++-- .../reference/text-indent-percentage-002-ref.html | 2 +- .../text-indent/text-indent-percentage-001.xht | 6 +++--- .../text-indent/text-indent-percentage-002.html | 7 ++----- .../text-indent/text-indent-percentage-003.html | 7 ++----- .../text-indent/text-indent-percentage-004.html | 7 ++----- 17 files changed, 24 insertions(+), 61 deletions(-) delete mode 100644 testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-001.xht.ini delete mode 100644 testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-002.html.ini delete mode 100644 testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-003.html.ini delete mode 100644 testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-004.html.ini diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index aea8b67b7d3f..8d3f1297fed3 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -219,17 +219,10 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord, // property amounts to anything. if (0 == mLineNumber && !HasPrevInFlow(mBlockReflowInput->mFrame)) { - const nsStyleCoord &textIndent = mStyleText->mTextIndent; - nscoord pctBasis = 0; - if (textIndent.HasPercent()) { - pctBasis = - mBlockReflowInput->GetContainingBlockContentISize(aWritingMode); - } - nscoord indent = textIndent.ComputeCoordPercentCalc(pctBasis); - - mTextIndent = indent; - - psd->mICoord += indent; + nscoord pctBasis = mBlockReflowInput->ComputedISize(); + mTextIndent = nsLayoutUtils::ResolveToLength(mStyleText->mTextIndent, + pctBasis); + psd->mICoord += mTextIndent; } PerFrameData* pfd = NewPerFrameData(mBlockReflowInput->mFrame); diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 0f2cc70d058b..8a7d607283e3 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -2045,7 +2045,7 @@ skip-if(isDebugBuild&&winWidget) == 1330051.svg 1330051-ref.svg == 1375674.html 1375674-ref.html == 1372041.html 1372041-ref.html == 1376092.html 1376092-ref.html -fuzzy-if(Android&&debug,1-1,1-1) needs-focus == 1377447-1.html 1377447-1-ref.html +fuzzy-if(Android,0-3,0-3) needs-focus == 1377447-1.html 1377447-1-ref.html needs-focus != 1377447-1.html 1377447-2.html == 1379041.html 1379041-ref.html == 1379696.html 1379696-ref.html diff --git a/layout/reftests/text-indent/text-indent-parent-dynamic-ref.html b/layout/reftests/text-indent/text-indent-parent-dynamic-ref.html index 8995a2727f45..8109f19e5986 100644 --- a/layout/reftests/text-indent/text-indent-parent-dynamic-ref.html +++ b/layout/reftests/text-indent/text-indent-parent-dynamic-ref.html @@ -3,7 +3,7 @@
-
X
+
X
diff --git a/layout/reftests/text-indent/text-indent-single-line-percent-ref.html b/layout/reftests/text-indent/text-indent-single-line-percent-ref.html index 8240ff74f05d..0eafe7c97cbb 100644 --- a/layout/reftests/text-indent/text-indent-single-line-percent-ref.html +++ b/layout/reftests/text-indent/text-indent-single-line-percent-ref.html @@ -3,7 +3,7 @@ text-indent test diff --git a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-001.xht.ini b/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-001.xht.ini deleted file mode 100644 index 8bbfee1878bd..000000000000 --- a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-001.xht.ini +++ /dev/null @@ -1,3 +0,0 @@ -[text-indent-percentage-001.xht] - expected: - if debug and not webrender and e10s and (os == "mac") and (version == "OS X 10.10.5") and (processor == "x86_64") and (bits == 64): FAIL diff --git a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-002.html.ini b/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-002.html.ini deleted file mode 100644 index 6969edd19784..000000000000 --- a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-002.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[text-indent-percentage-002.html] - expected: FAIL diff --git a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-003.html.ini b/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-003.html.ini deleted file mode 100644 index 935bca6121bb..000000000000 --- a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-003.html.ini +++ /dev/null @@ -1,6 +0,0 @@ -[text-indent-percentage-003.html] - expected: - if debug and not webrender and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if not debug and not webrender and e10s and (os == "win") and (version == "6.1.7601") and (processor == "x86") and (bits == 32): FAIL - if debug and not webrender and e10s and (os == "win") and (version == "10.0.15063") and (processor == "x86_64") and (bits == 64): FAIL - if not debug and not webrender and e10s and (os == "win") and (version == "10.0.15063") and (processor == "x86_64") and (bits == 64): FAIL diff --git a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-004.html.ini b/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-004.html.ini deleted file mode 100644 index 3bf7fa2a1f1b..000000000000 --- a/testing/web-platform/meta/css/css-text/text-indent/text-indent-percentage-004.html.ini +++ /dev/null @@ -1,2 +0,0 @@ -[text-indent-percentage-004.html] - expected: FAIL diff --git a/testing/web-platform/tests/css/CSS2/css1/c547-indent-001-ref.xht b/testing/web-platform/tests/css/CSS2/css1/c547-indent-001-ref.xht index f66ec9432a23..013a5414bc01 100644 --- a/testing/web-platform/tests/css/CSS2/css1/c547-indent-001-ref.xht +++ b/testing/web-platform/tests/css/CSS2/css1/c547-indent-001-ref.xht @@ -32,13 +32,7 @@ margin-top: 0em; } - div#X - { - float: left; - margin-left: 50%; - } - - div#after-X + div { background-color: aqua; width: 25%; @@ -58,9 +52,7 @@ the others should all be
aligned on the left of the window.

-
X
- -

The X on the previous line should be centered across the window.
+
X The first X in this sentence should be indented to the center of this block.
diff --git a/testing/web-platform/tests/css/CSS2/css1/c547-indent-001.xht b/testing/web-platform/tests/css/CSS2/css1/c547-indent-001.xht index 0e9d67321162..e38562f7f4de 100644 --- a/testing/web-platform/tests/css/CSS2/css1/c547-indent-001.xht +++ b/testing/web-platform/tests/css/CSS2/css1/c547-indent-001.xht @@ -27,7 +27,7 @@ aligned on the left of the window.

- X The X on the previous line should be centered across the window. + X The first X in this sentence should be indented to the center of this block.
diff --git a/testing/web-platform/tests/css/CSS2/text/text-indent-percent-001-ref.xht b/testing/web-platform/tests/css/CSS2/text/text-indent-percent-001-ref.xht index ed9428c72e64..335ed62bbbbc 100644 --- a/testing/web-platform/tests/css/CSS2/text/text-indent-percent-001-ref.xht +++ b/testing/web-platform/tests/css/CSS2/text/text-indent-percent-001-ref.xht @@ -2,7 +2,7 @@ text-indent test @@ -11,4 +11,4 @@ p { width: 300px; text-indent: 50px; } - \ No newline at end of file + diff --git a/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-001-ref.xht b/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-001-ref.xht index 546ba57a9889..b8e8d62a08ac 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-001-ref.xht +++ b/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-001-ref.xht @@ -19,7 +19,7 @@

Test passes if there is no red visible on the page.

-
X
+
X

Test passes if the following two text blocks look same in terms of margin-left and text-indent respectively.

@@ -31,4 +31,4 @@ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ.
- \ No newline at end of file + diff --git a/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-002-ref.html b/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-002-ref.html index 5b3bc918d15f..5c9f5aa4bfc3 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-002-ref.html +++ b/testing/web-platform/tests/css/css-text/text-indent/reference/text-indent-percentage-002-ref.html @@ -4,8 +4,8 @@ CSS Text Test reference -

Test passes if there is a single black X below and no red.

X
diff --git a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-001.xht b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-001.xht index ae2478579d21..dd732c872151 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-001.xht +++ b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-001.xht @@ -18,7 +18,7 @@ #reference1 { color: red; - left: 0; + left: 100px; /* see comments for #test1 below */ position: absolute; top: 0; z-index: -1; @@ -29,8 +29,8 @@ } #test1 { - text-indent: 50%; - margin-left: -50%; + margin-left: -50%; /* -50% * 400px = -200px which makes the inline-size of this block 600px */ + text-indent: 50%; /* 50% * 600px = 300px (which is 100px from the start of #parent due to the negative margin) */ } #test2 { diff --git a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-002.html b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-002.html index 65969260c5ee..6ccbad5b11b7 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-002.html +++ b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-002.html @@ -8,7 +8,7 @@ -

Test passes if there is a single black X below and no red.

X
-
X
diff --git a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-003.html b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-003.html index f81390da873d..4564a069e3ca 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-003.html +++ b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-003.html @@ -8,7 +8,7 @@ -

Test passes if there is a single black X below and no red.

X
-
X
diff --git a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-004.html b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-004.html index 73f4c219558b..37a7ea7eb655 100644 --- a/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-004.html +++ b/testing/web-platform/tests/css/css-text/text-indent/text-indent-percentage-004.html @@ -8,7 +8,7 @@ -

Test passes if there is a single black X below and no red.

X
-
X
From 0feccf9fd7863534ed5b1fcf3d867707e9588829 Mon Sep 17 00:00:00 2001 From: Mats Palmgren Date: Thu, 25 Oct 2018 16:51:45 +0200 Subject: [PATCH 15/26] Bug 1500530 - Make the anonymous child