mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:43:44 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1013814 - add inIDOMUtils.getRelativeRuleLine; r=heycam,pbrosset (60153c71f7)
- Bug 1197930 - Add comments for getRuleLine and getRuleColumn. r=heycam (6c65131f95)
- Bug 1157292 - include XBL stylesheets in the inspector's list of stylesheets, r=dholbert,heycam (f3ecad41c2)
- Bug 1187409 - make CssPropertyIsShorthand handle CSS variables r=heycam (6dcba2f01b)
- Bug 1142206 - Let GetSubpropertiesForCSSProperty handle custom property. r=heycam, r=pbrosset (f86eba559a)
- Bug 1201136 - treat "currentColor" as a valid color. r=heycam (f868825389)
- Bug 180118 - Part 5: Add a RestyleHintData outparam to HasAttributeDependentStyle for use with eRestyle_SomeDescendants. r=bzbarsky (fab0ecdf39)
- Bug 1206356: Add mfbt/Random.h, implementing the xorshift128+ random number generator. r=waldo (1928e47e21)
- Bug 1197421 - Fix promise worker proxy cleanup and update callers. r=catalinb (2128787815)
- Bug 1197421 - Fetch resolver uses PromiseWorkerProxy. r=catalinb (d8611f0bcc)
- Bug 1180118 - Part 7: Split out FindClosestRestyleRoot and allow passing in a pre-computed restyle root to AddPendingRestyle. r=bzbarsky (b783859d8a)
- Bug 1180118 - Part 8: Keep track of the closest restyle root in AddPendingRestylesForDescendantsMatchingSelectors. r=bzbarsky (cf9d1b35b6)
- Bug 1180118 - Part 9: Clear nsCSSSelector pointers in the pending restyle tracker if they might be stale. r=bzbarsky (13faac05f3)
- Bug 1180118 - Part 10: Logging. r=bzbarsky (79f71825ca)
- Bug 1180118 - Part 11: Use ReparentStyleContext even if eRestyle_SomeDescendants is used. r=bzbarsky (9f8e218aac)
- Bug 1187851 patch 1 - Tests for making dynamic changes to filter and perspective change fixed position containing block for descendants. r=roc (82bbd8b750)
- Bug 1187851 patch 2 - Cleanup to prepare for making dynamic changes to filter and perspective change fixed position containing block for descendants. r=roc (9fc38132ac)
- Bug 1187851 patch 3 - Rename nsChangeHint_AddOrRemoveTransform to nsChangeHint_UpdateContainingBlock. r=roc (25e50c5ac5)
- Bug 1187851 patch 5 - Make dynamic changes to perspective change fixed position containing block for descendants. r=roc (df51439c10)
- Bug 1203766 - Part 1: Generate nsPresArena::ObjectIDs with a preprocessor-included file. r=bzbarsky (18e36acbd9)
- Bug 1203766 - Part 2: Add an ArenaRefPtr class that can have its pointer cleared out when an object's owning nsPresArena goes away. r=bzbarsky (ff06cd91e0)
- Bug 1203766 - Part 3: Add ArenaRefPtr support to nsStyleContext. r=bzbarsky (f1b52960f2)
- Bug 1203766 - Part 4: Add a "restyle generation" counter, which increments whenever we process pending restyles. r=bzbarsky (b54d7e5ec9)
- Bug 1203766 - Part 5: Rename nsComputedDOMStyle::mStyleContextHolder to mStyleContext. r=bzbarsky (5fa2d18667)
- Bug 1203766 - Part 6: Cache resolved style contexts on nsComputedDOMStyle to avoid re-resolving if styles haven't changed. r=bzbarsky (de84fc67e7)
- Bug 1203766 - Part 6.1: Clear cached style context on nsComputedDOMStyle when its element is moved. r=bzbarsky (d43394515a)
- Bug 1203766 - Part 7: Test. r=bzbarsky (59c7ea8c81)
- Bug 1203766 - Unified compilation fixes. (61137c44a5)
- Bug 1151829 - Unbreak build on non-SPS platforms after bug 1093934. (e9188d7c56)
- Bug 1202512 - Part 1: Add Element flags to record whether an eRestyle_SomeDescendants restyle is pending for it. r=bzbarsky (7f6dbef338)
- Bug 1197620 - Part 1 - Stop all animations in destroyed frames. r=bbirtles (829b1635db)
- Bug 1197620 - Part 2 tests that animation stop playing when its element is not displayed. r=bbirtles (87597b5125)
- Bug 1190254 - Use same conditions to call ReparentStyleContext in RestyleUndisplayedNodes as in RestyleSelf. r=mats (7e778822b3)
- Bug 1181011 - Don't use cached rule node structs for animations within pseudo-elements. r=dbaron a=abillings (966b351dcd)
- Bug 1180120 - Part 1: Record on style contexts that reset style is explicitly inherited. r=dbaron (50b4f4e76a)
- Bug 1180120 - Part 2: Move style-if-visited as well in nsStyleContext::Move (and assert that its parent is the same as the non-visited-style parent). r=dbaron (fd34448459)
- Bug 1180120 - Part 3: Record on ElementRestyler whether we are at the root of a restyle. r=dbaron (edeb469544)
- Bug 1180120 - Part 4: Add an outparam to CalcStyleDifference to indicate which struct pointers were identical. r=dbaron (1410e5ce05)
- Bug 1180120 - Part 5: Factor out section of ElementRestyler::Restyle that calls AddPendingRestylesForDescendantsMatchingSelectors. r=dbaron (ab5b899c7f)
- Bug 1180120 - Part 6: Replace HasSameCachedStyleData call with samePointerStructs bit tests. r=dbaron (3654cb6db8)
- Bug 1180120 - Part 6.1: Factor out some of RestyleUndisplayedDescendants. r=dbaron (882a535699)
- Bug 1180120 - Part 6.2: Refactor MaybeReframeFor{Before,After}Pseudo. r=dbaron (99ccd305ca)
- Bug 1180120 - Part 7: Add eRestyleResult_StopWithStyleChange. r=dbaron (6626dd8133)
- Bug 1192302 - Part 1: Make MustCheckUndisplayedContent take its frame as an argument. r=bzbarsky (7ae5bcc569)
- Bug 1192302 - Part 2: Traverse the frame tree when processing eRestyle_SomeDescendants. r=bzbarsky (71b325d22e)
- Bug 1206996: Use range-based 'for' syntax to iterate across nsFrameLists in RestyleManager. r=tn (a2c8e0fa73)
- Bug 1163875 - ensure opacity animation in patterns results in redraws r=jwatt (7fd1f5c55a)
- Bug 1180036 - Replace the warning that anonymous nodes should not be in child lists with an assert plus whitelisting of known-OK cases. r=bz (0c9dd01766)
- Bug 1169440 patch 4 - Add comment to nsStylePadding::DifferenceAlwaysHandledForDescendants. r=heycam (2483adc4a0)
- Bug 1169440 patch 5 - Adjust hints in CalcDifference methods to emit new nsChangeHint_ReflowChangesSizeOrPosition hint. r=heycam (b1ad73ab5f)
- Bug 1169440 patch 6 - Add parameter to nsIFrame::FrameNeedsReflow to control handling of target being a reflow root. r=dholbert (c75a63eb67)
- Bug 1169440 patch 7 - Pass parameter determined from style hint to FrameNeedsReflow. r=dholbert (ee02625c5a)
- Bug 1198894: Use nsChangeHint_RepaintFrame instead of NS_STYLE_HINT_VISUAL to trigger simple repaints in nsStyleStruct.cpp CalcDifference methods. r=heycam (770bb3c11c)
- Bug 417178 - "Google reader does not show subscribed topics in ff3b3 at certain zoom levels" [p=roc@ocallahan.org (Robert O'Callahan [roc]) r+sr=dbaron a1.9b5=mconnor] (a9b8541d23)
- Bug 1203472 - [css-grid] Add missing |mIsSubgrid| check. r=simon.sapin@exyr.org (d68050a108)
- Bug 1141919 - Fix incomplete line break suppression in ruby. r=dbaron (087a824358)
- Bug 1157011 - Check line break suppression of BR frame from its parent frame. r=dholbert (5572f7bc56)
- Bug 1134849 - For display:inline elements whose writing mode is orthogonal to their parent's, the computed value should become inline-block. r=dbaron (0df244841c)
- Bug 1196887 - Compare the writing-mode property, not only whether it is horizontal or vertical, when deciding whether to compute display:inline as inline-block. r=dholbert (a0c4500a83)
- Bug 1140198 - display:contents on the root element (but not else-where) should compute to 'block'. r=roc (606663d0c9)
- Bug 1188061 - Pass the style context to nsStylePosition::CalcDifference so that it can take account of writing-mode where necessary. r=dbaron (6728d9d865)
- Bug 1181907 (Part 1) - Make it possible to use nsGenericHashKey with free functions. r=heycam (c304448825)
- Bug 1181907 (Part 2) - Make nsCSSProperty hashable. r=heycam (4fff3bb968)
- Bug 1181907 (Part 3) - Add CSSVariableImageTable and use it to store ImageValues generated by CSS variables. r=heycam (8431589452)
- Bug 1139723 - Turn on expensive style struct assertions for 1136010-1.html, and fix pref name typo. r=dbaron (f20387295b)
- Bug 1151214 part 1 - Remove the optimization to ignore 'align-content' changes for single-line flex containers. It's invalid now that we'll support 'align-content' for other box types (grid). r=dbaron (aa21e1a3a4)
- No bug. Add comment to nsStyleClipPath::ReleaseRef explaining why only one member is nulled out. r=me (NPOTB) (19d5eb5fb1)
- Bug 1202993 - Remove the logical-direction-based keywords for caption-side, and instead interpret the old physical keywords as logical sides. r=dholbert (0f33c4a767)
- Bug 1177149 - Don't force an invalidation for transform origin changes. r=dbaron (8a134525e0)
- Bug 1191855 - Make the intrinsic size of <iframe> remain physical 300x150, regardless of writing mode. r=dholbert (64d897f218)
- Bug 1099557 - Make -moz-control-character-visibility default to 'visible' rather than 'hidden', so that spurious control characters are rendered as hexboxes. r=dbaron (ef6eed92c2)
- align to FF (1d931574ae)
- Bug 1141926 - Check nsCaret visibility when NotifySelectionChanged. r=roc (d23f1422e2)
This commit is contained in:
@@ -64,3 +64,6 @@ support-files = document-timeline/file_document-timeline.html
|
||||
skip-if = buildapp == 'mulet'
|
||||
[mozilla/test_deferred_start.html]
|
||||
support-files = mozilla/file_deferred_start.html
|
||||
skip-if = (toolkit == 'gonk' && debug)
|
||||
[mozilla/test_hide_and_show.html]
|
||||
support-files = mozilla/file_hide_and_show.html
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<script src="../testcommon.js"></script>
|
||||
<style>
|
||||
@keyframes move {
|
||||
100% {
|
||||
transform: translateX(100px);
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t, { style: 'animation: move 100s infinite' });
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'display:initial element has animations');
|
||||
|
||||
div.style.display = 'none';
|
||||
assert_equals(div.getAnimations().length, 0,
|
||||
'display:none element has no animations');
|
||||
}, 'Animation stops playing when the element style display is set to "none"');
|
||||
|
||||
test(function(t) {
|
||||
var parentElement = addDiv(t);
|
||||
var div = addDiv(t, { style: 'animation: move 100s infinite' });
|
||||
parentElement.appendChild(div);
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'display:initial element has animations');
|
||||
|
||||
parentElement.style.display = 'none';
|
||||
assert_equals(div.getAnimations().length, 0,
|
||||
'Element in display:none subtree has no animations');
|
||||
}, 'Animation stops playing when its parent element style display is set ' +
|
||||
'to "none"');
|
||||
|
||||
test(function(t) {
|
||||
var div = addDiv(t, { style: 'animation: move 100s infinite' });
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'display:initial element has animations');
|
||||
|
||||
div.style.display = 'none';
|
||||
assert_equals(div.getAnimations().length, 0,
|
||||
'display:none element has no animations');
|
||||
|
||||
div.style.display = '';
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'Element which is no longer display:none has animations ' +
|
||||
'again');
|
||||
}, 'Animation starts playing when the element gets shown from ' +
|
||||
'"display:none" state');
|
||||
|
||||
test(function(t) {
|
||||
var parentElement = addDiv(t);
|
||||
var div = addDiv(t, { style: 'animation: move 100s infinite' });
|
||||
parentElement.appendChild(div);
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'display:initial element has animations');
|
||||
|
||||
parentElement.style.display = 'none';
|
||||
assert_equals(div.getAnimations().length, 0,
|
||||
'Element in display:none subtree has no animations');
|
||||
|
||||
parentElement.style.display = '';
|
||||
assert_equals(div.getAnimations().length, 1,
|
||||
'Element which is no longer in display:none subtree has ' +
|
||||
'animations again');
|
||||
}, 'Animation starts playing when its parent element is shown from ' +
|
||||
'"display:none" state');
|
||||
|
||||
done();
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id="log"></div>
|
||||
<script>
|
||||
'use strict';
|
||||
setup({explicit_done: true});
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ "set": [["dom.animations-api.core.enabled", true]]},
|
||||
function() {
|
||||
window.open("file_hide_and_show.html");
|
||||
});
|
||||
</script>
|
||||
+17
-8
@@ -89,18 +89,27 @@ enum {
|
||||
// change will attempt to restyle descendants).
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT = ELEMENT_FLAG_BIT(3),
|
||||
|
||||
// All of those bits together, for convenience.
|
||||
ELEMENT_ALL_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
|
||||
ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT,
|
||||
// Set if this element has a pending restyle with an eRestyle_SomeDescendants
|
||||
// restyle hint.
|
||||
ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR = ELEMENT_FLAG_BIT(4),
|
||||
|
||||
// Just the HAS_PENDING bits, for convenience
|
||||
ELEMENT_PENDING_RESTYLE_FLAGS = ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE,
|
||||
ELEMENT_PENDING_RESTYLE_FLAGS =
|
||||
ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE,
|
||||
|
||||
// Just the IS_POTENTIAL bits, for convenience
|
||||
ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS =
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
|
||||
ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT,
|
||||
|
||||
// All of the restyle bits together, for convenience.
|
||||
ELEMENT_ALL_RESTYLE_FLAGS = ELEMENT_PENDING_RESTYLE_FLAGS |
|
||||
ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS |
|
||||
ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR,
|
||||
|
||||
// Remaining bits are for subclasses
|
||||
ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 4
|
||||
ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 5
|
||||
};
|
||||
|
||||
#undef ELEMENT_FLAG_BIT
|
||||
|
||||
@@ -13,8 +13,8 @@ class nsICSSLoaderObserver;
|
||||
class nsIURI;
|
||||
|
||||
#define NS_ISTYLESHEETLINKINGELEMENT_IID \
|
||||
{ 0xe5855604, 0x8a9a, 0x4181, \
|
||||
{ 0xbe, 0x41, 0xdd, 0xf7, 0x08, 0x70, 0x3f, 0xbe } }
|
||||
{ 0xa8b79f3b, 0x9d18, 0x4f9c, \
|
||||
{ 0xb1, 0xaa, 0x8c, 0x9b, 0x1b, 0xaa, 0xac, 0xad } }
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
@@ -97,6 +97,14 @@ public:
|
||||
// some types of linking elements, but it's a better place than
|
||||
// anywhere else.
|
||||
virtual void SetLineNumber(uint32_t aLineNumber) = 0;
|
||||
|
||||
/**
|
||||
* Get the line number, as previously set by SetLineNumber.
|
||||
*
|
||||
* @return the line number of this element; or 1 if no line number
|
||||
* was set
|
||||
*/
|
||||
virtual uint32_t GetLineNumber() = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheetLinkingElement,
|
||||
|
||||
@@ -129,6 +129,12 @@ nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
|
||||
mLineNumber = aLineNumber;
|
||||
}
|
||||
|
||||
/* virtual */ uint32_t
|
||||
nsStyleLinkElement::GetLineNumber()
|
||||
{
|
||||
return mLineNumber;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsStyleLinkElement::IsImportEnabled()
|
||||
{
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
|
||||
virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
|
||||
virtual void SetLineNumber(uint32_t aLineNumber) override;
|
||||
virtual uint32_t GetLineNumber() override;
|
||||
|
||||
enum RelValue {
|
||||
ePREFETCH = 0x00000001,
|
||||
|
||||
+68
-105
@@ -27,6 +27,7 @@
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseWorkerProxy.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
@@ -47,28 +48,27 @@ namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
class WorkerFetchResolver final : public FetchDriverObserver,
|
||||
public WorkerFeature
|
||||
class WorkerFetchResolver final : public FetchDriverObserver
|
||||
{
|
||||
friend class MainThreadFetchRunnable;
|
||||
friend class WorkerFetchResponseEndRunnable;
|
||||
friend class WorkerFetchResponseRunnable;
|
||||
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
Mutex mCleanUpLock;
|
||||
bool mCleanedUp;
|
||||
// The following are initialized and used exclusively on the worker thread.
|
||||
nsRefPtr<Promise> mFetchPromise;
|
||||
nsRefPtr<Response> mResponse;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
public:
|
||||
|
||||
WorkerFetchResolver(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
, mCleanUpLock("WorkerFetchResolver")
|
||||
, mCleanedUp(false)
|
||||
, mFetchPromise(aPromise)
|
||||
// Returns null if worker is shutting down.
|
||||
static already_AddRefed<WorkerFetchResolver>
|
||||
Create(workers::WorkerPrivate* aWorkerPrivate, Promise* aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
|
||||
if (!proxy) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerFetchResolver> r = new WorkerFetchResolver(proxy);
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -77,58 +77,16 @@ public:
|
||||
void
|
||||
OnResponseEnd() override;
|
||||
|
||||
bool
|
||||
Notify(JSContext* aCx, Status aStatus) override
|
||||
{
|
||||
if (aStatus > Running) {
|
||||
CleanUp(aCx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CleanUp(JSContext* aCx)
|
||||
{
|
||||
MutexAutoLock lock(mCleanUpLock);
|
||||
|
||||
if (mCleanedUp) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
|
||||
|
||||
mWorkerPrivate->RemoveFeature(aCx, this);
|
||||
CleanUpUnchecked();
|
||||
}
|
||||
|
||||
void
|
||||
CleanUpUnchecked()
|
||||
{
|
||||
mResponse = nullptr;
|
||||
if (mFetchPromise) {
|
||||
mFetchPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
mFetchPromise = nullptr;
|
||||
}
|
||||
mCleanedUp = true;
|
||||
}
|
||||
|
||||
workers::WorkerPrivate*
|
||||
GetWorkerPrivate() const
|
||||
{
|
||||
// It's ok to race on |mCleanedUp|, because it will never cause us to fire
|
||||
// the assertion when we should not.
|
||||
MOZ_ASSERT(!mCleanedUp);
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
private:
|
||||
~WorkerFetchResolver()
|
||||
explicit WorkerFetchResolver(PromiseWorkerProxy* aProxy)
|
||||
: mPromiseProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(mCleanedUp);
|
||||
MOZ_ASSERT(!mFetchPromise);
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
|
||||
~WorkerFetchResolver()
|
||||
{}
|
||||
};
|
||||
|
||||
class MainThreadFetchResolver final : public FetchDriverObserver
|
||||
@@ -153,34 +111,31 @@ class MainThreadFetchRunnable : public nsRunnable
|
||||
nsRefPtr<InternalRequest> mRequest;
|
||||
|
||||
public:
|
||||
MainThreadFetchRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aPromise,
|
||||
MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
|
||||
InternalRequest* aRequest)
|
||||
: mResolver(new WorkerFetchResolver(aWorkerPrivate, aPromise))
|
||||
: mResolver(aResolver)
|
||||
, mRequest(aRequest)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
if (!aWorkerPrivate->AddFeature(aWorkerPrivate->GetJSContext(), mResolver)) {
|
||||
NS_WARNING("Could not add WorkerFetchResolver feature to worker");
|
||||
mResolver->CleanUpUnchecked();
|
||||
mResolver = nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mResolver);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
// AddFeature() call failed, don't bother running.
|
||||
if (!mResolver) {
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mResolver->mPromiseProxy;
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
NS_WARNING("Aborting Fetch because worker already shut down");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = mResolver->GetWorkerPrivate()->GetPrincipal();
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = mResolver->GetWorkerPrivate()->GetLoadGroup();
|
||||
nsCOMPtr<nsIPrincipal> principal = proxy->GetWorkerPrivate()->GetPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = proxy->GetWorkerPrivate()->GetLoadGroup();
|
||||
MOZ_ASSERT(loadGroup);
|
||||
nsRefPtr<FetchDriver> fetch = new FetchDriver(mRequest, principal, loadGroup);
|
||||
nsIDocument* doc = mResolver->GetWorkerPrivate()->GetDocument();
|
||||
nsIDocument* doc = proxy->GetWorkerPrivate()->GetDocument();
|
||||
if (doc) {
|
||||
fetch->SetDocument(doc);
|
||||
}
|
||||
@@ -262,10 +217,15 @@ FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
|
||||
r->SetSkipServiceWorker();
|
||||
}
|
||||
|
||||
nsRefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(worker, p, r);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(run))) {
|
||||
NS_WARNING("MainThreadFetchRunnable dispatch failed!");
|
||||
nsRefPtr<WorkerFetchResolver> resolver = WorkerFetchResolver::Create(worker, p);
|
||||
if (!resolver) {
|
||||
NS_WARNING("Could not add WorkerFetchResolver feature to worker");
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(resolver, r);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(run)));
|
||||
}
|
||||
|
||||
return p.forget();
|
||||
@@ -304,8 +264,10 @@ class WorkerFetchResponseRunnable final : public WorkerRunnable
|
||||
// Passed from main thread to worker thread after being initialized.
|
||||
nsRefPtr<InternalResponse> mInternalResponse;
|
||||
public:
|
||||
WorkerFetchResponseRunnable(WorkerFetchResolver* aResolver, InternalResponse* aResponse)
|
||||
: WorkerRunnable(aResolver->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
WorkerFetchResolver* aResolver,
|
||||
InternalResponse* aResponse)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mResolver(aResolver)
|
||||
, mInternalResponse(aResponse)
|
||||
{
|
||||
@@ -316,15 +278,13 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aWorkerPrivate == mResolver->GetWorkerPrivate());
|
||||
|
||||
nsRefPtr<Promise> promise = mResolver->mFetchPromise.forget();
|
||||
nsRefPtr<Promise> promise = mResolver->mPromiseProxy->WorkerPromise();
|
||||
|
||||
if (mInternalResponse->Type() != ResponseType::Error) {
|
||||
nsRefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
|
||||
mResolver->mResponse = new Response(global, mInternalResponse);
|
||||
|
||||
promise->MaybeResolve(mResolver->mResponse);
|
||||
nsRefPtr<Response> response = new Response(global, mInternalResponse);
|
||||
promise->MaybeResolve(response);
|
||||
} else {
|
||||
ErrorResult result;
|
||||
result.ThrowTypeError(MSG_FETCH_FAILED);
|
||||
@@ -338,8 +298,9 @@ class WorkerFetchResponseEndRunnable final : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<WorkerFetchResolver> mResolver;
|
||||
public:
|
||||
explicit WorkerFetchResponseEndRunnable(WorkerFetchResolver* aResolver)
|
||||
: WorkerRunnable(aResolver->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
WorkerFetchResolver* aResolver)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mResolver(aResolver)
|
||||
{
|
||||
}
|
||||
@@ -349,9 +310,8 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aWorkerPrivate == mResolver->GetWorkerPrivate());
|
||||
|
||||
mResolver->CleanUp(aCx);
|
||||
mResolver->mPromiseProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -361,17 +321,19 @@ WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mCleanUpLock);
|
||||
if (mCleanedUp) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerFetchResponseRunnable> r =
|
||||
new WorkerFetchResponseRunnable(this, aResponse);
|
||||
new WorkerFetchResponseRunnable(mPromiseProxy->GetWorkerPrivate(), this,
|
||||
aResponse);
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
if (!r->Dispatch(cx)) {
|
||||
NS_WARNING("Could not dispatch fetch resolve");
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
NS_WARNING("Could not dispatch fetch response");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,17 +341,18 @@ void
|
||||
WorkerFetchResolver::OnResponseEnd()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mCleanUpLock);
|
||||
if (mCleanedUp) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerFetchResponseEndRunnable> r =
|
||||
new WorkerFetchResponseEndRunnable(this);
|
||||
new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(), this);
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
if (!r->Dispatch(cx)) {
|
||||
NS_WARNING("Could not dispatch fetch resolve end");
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
NS_WARNING("Could not dispatch fetch response end");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1712,7 +1712,7 @@ public:
|
||||
void
|
||||
WorkerRunInternal(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
nsRefPtr<Promise> workerPromise = mPromiseProxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> workerPromise = mPromiseProxy->WorkerPromise();
|
||||
|
||||
ErrorResult result;
|
||||
nsAutoTArray<nsRefPtr<Notification>, 5> notifications;
|
||||
@@ -1761,27 +1761,19 @@ public:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mPromiseProxy, "Was Done() called twice?");
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mPromiseProxy->GetWorkerPrivate());
|
||||
nsRefPtr<WorkerGetResultRunnable> r =
|
||||
new WorkerGetResultRunnable(mPromiseProxy->GetWorkerPrivate(),
|
||||
mPromiseProxy,
|
||||
new WorkerGetResultRunnable(proxy->GetWorkerPrivate(),
|
||||
proxy,
|
||||
Move(mStrings));
|
||||
|
||||
if (!r->Dispatch(aCx)) {
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(mPromiseProxy->GetWorkerPrivate(),
|
||||
mPromiseProxy);
|
||||
|
||||
DebugOnly<bool> ok = cr->Dispatch(aCx);
|
||||
MOZ_ASSERT(ok);
|
||||
}
|
||||
|
||||
mPromiseProxy = nullptr;
|
||||
r->Dispatch(aCx);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1798,31 +1790,18 @@ class WorkerGetRunnable final : public nsRunnable
|
||||
const nsString mTag;
|
||||
const nsString mScope;
|
||||
public:
|
||||
WorkerGetRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aWorkerPromise,
|
||||
WorkerGetRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aTag,
|
||||
const nsAString& aScope)
|
||||
: mTag(aTag), mScope(aScope)
|
||||
: mPromiseProxy(aProxy), mTag(aTag), mScope(aScope)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
mPromiseProxy =
|
||||
PromiseWorkerProxy::Create(aWorkerPrivate,
|
||||
aWorkerPromise);
|
||||
|
||||
if (!mPromiseProxy || !mPromiseProxy->GetWorkerPromise()) {
|
||||
aWorkerPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
mPromiseProxy = nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (!mPromiseProxy) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsINotificationStorageCallback> callback =
|
||||
new WorkerGetCallback(mPromiseProxy, mScope);
|
||||
|
||||
@@ -1837,8 +1816,8 @@ public:
|
||||
return rv;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -1877,13 +1856,18 @@ Notification::WorkerGet(WorkerPrivate* aWorkerPrivate,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerGetRunnable> r =
|
||||
new WorkerGetRunnable(aWorkerPrivate, p, aFilter.mTag, aScope);
|
||||
if (NS_WARN_IF(NS_FAILED(NS_DispatchToMainThread(r)))) {
|
||||
nsRefPtr<PromiseWorkerProxy> proxy =
|
||||
PromiseWorkerProxy::Create(aWorkerPrivate, p);
|
||||
if (!proxy) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerGetRunnable> r =
|
||||
new WorkerGetRunnable(proxy, aFilter.mTag, aScope);
|
||||
// Since this is called from script via
|
||||
// ServiceWorkerRegistration::GetNotifications, we can assert dispatch.
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
return p.forget();
|
||||
}
|
||||
|
||||
|
||||
+82
-59
@@ -1509,8 +1509,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate == mWorkerPrivate);
|
||||
|
||||
MOZ_ASSERT(mPromiseWorkerProxy);
|
||||
nsRefPtr<Promise> workerPromise = mPromiseWorkerProxy->GetWorkerPromise();
|
||||
MOZ_ASSERT(workerPromise);
|
||||
nsRefPtr<Promise> workerPromise = mPromiseWorkerProxy->WorkerPromise();
|
||||
|
||||
// Here we convert the buffer to a JS::Value.
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
@@ -1553,11 +1552,10 @@ PromiseWorkerProxy::Create(workers::WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
// We do this to make sure the worker thread won't shut down before the
|
||||
// promise is resolved/rejected on the worker thread.
|
||||
if (!aWorkerPrivate->AddFeature(aWorkerPrivate->GetJSContext(), proxy)) {
|
||||
if (!proxy->AddRefObject()) {
|
||||
// Probably the worker is terminating. We cannot complete the operation
|
||||
// and we have to release all the resources.
|
||||
proxy->mCleanedUp = true;
|
||||
proxy->mWorkerPromise = nullptr;
|
||||
proxy->CleanProperties();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1574,40 +1572,76 @@ PromiseWorkerProxy::PromiseWorkerProxy(workers::WorkerPrivate* aWorkerPrivate,
|
||||
, mCleanedUp(false)
|
||||
, mCallbacks(aCallbacks)
|
||||
, mCleanUpLock("cleanUpLock")
|
||||
, mFeatureAdded(false)
|
||||
{
|
||||
}
|
||||
|
||||
PromiseWorkerProxy::~PromiseWorkerProxy()
|
||||
{
|
||||
MOZ_ASSERT(mCleanedUp);
|
||||
MOZ_ASSERT(!mFeatureAdded);
|
||||
MOZ_ASSERT(!mWorkerPromise);
|
||||
MOZ_ASSERT(!mWorkerPrivate);
|
||||
}
|
||||
|
||||
workers::WorkerPrivate*
|
||||
PromiseWorkerProxy::GetWorkerPrivate() const
|
||||
void
|
||||
PromiseWorkerProxy::CleanProperties()
|
||||
{
|
||||
// It's ok to race on |mCleanedUp|, because it will never cause us to fire
|
||||
// the assertion when we should not.
|
||||
MOZ_ASSERT(!mCleanedUp);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (NS_IsMainThread()) {
|
||||
mCleanUpLock.AssertCurrentThreadOwns();
|
||||
}
|
||||
#endif
|
||||
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
Promise*
|
||||
PromiseWorkerProxy::GetWorkerPromise() const
|
||||
{
|
||||
|
||||
#ifdef DEBUG
|
||||
workers::WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
// Ok to do this unprotected from Create().
|
||||
// CleanUp() holds the lock before calling this.
|
||||
mCleanedUp = true;
|
||||
mWorkerPromise = nullptr;
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
PromiseWorkerProxy::AddRefObject()
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(!mFeatureAdded);
|
||||
if (!mWorkerPrivate->AddFeature(mWorkerPrivate->GetJSContext(),
|
||||
this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFeatureAdded = true;
|
||||
// Maintain a reference so that we have a valid object to clean up when
|
||||
// removing the feature.
|
||||
AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
workers::WorkerPrivate*
|
||||
PromiseWorkerProxy::GetWorkerPrivate() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (NS_IsMainThread()) {
|
||||
mCleanUpLock.AssertCurrentThreadOwns();
|
||||
}
|
||||
#endif
|
||||
// Safe to check this without a lock since we assert lock ownership on the
|
||||
// main thread above.
|
||||
MOZ_ASSERT(!mCleanedUp);
|
||||
MOZ_ASSERT(mFeatureAdded);
|
||||
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
Promise*
|
||||
PromiseWorkerProxy::WorkerPromise() const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
workers::WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
worker->AssertIsOnWorkerThread();
|
||||
#endif
|
||||
MOZ_ASSERT(mWorkerPromise);
|
||||
return mWorkerPromise;
|
||||
}
|
||||
|
||||
@@ -1621,14 +1655,6 @@ PromiseWorkerProxy::StoreISupports(nsISupports* aSupports)
|
||||
mSupportsArray.AppendElement(supports);
|
||||
}
|
||||
|
||||
bool
|
||||
PromiseWorkerProxyControlRunnable::WorkerRun(JSContext* aCx,
|
||||
workers::WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PromiseWorkerProxy::RunCallback(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
@@ -1636,9 +1662,9 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MutexAutoLock lock(GetCleanUpLock());
|
||||
MutexAutoLock lock(Lock());
|
||||
// If the worker thread's been cancelled we don't need to resolve the Promise.
|
||||
if (IsClean()) {
|
||||
if (CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1657,11 +1683,7 @@ PromiseWorkerProxy::RunCallback(JSContext* aCx,
|
||||
Move(buffer),
|
||||
aFunc);
|
||||
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
nsRefPtr<WorkerControlRunnable> runnable =
|
||||
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, this);
|
||||
mWorkerPrivate->DispatchControlRunnable(runnable.forget());
|
||||
}
|
||||
runnable->Dispatch(aCx);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1681,10 +1703,6 @@ PromiseWorkerProxy::RejectedCallback(JSContext* aCx,
|
||||
bool
|
||||
PromiseWorkerProxy::Notify(JSContext* aCx, Status aStatus)
|
||||
{
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
|
||||
|
||||
if (aStatus >= Canceling) {
|
||||
CleanUp(aCx);
|
||||
}
|
||||
@@ -1695,24 +1713,29 @@ PromiseWorkerProxy::Notify(JSContext* aCx, Status aStatus)
|
||||
void
|
||||
PromiseWorkerProxy::CleanUp(JSContext* aCx)
|
||||
{
|
||||
MutexAutoLock lock(mCleanUpLock);
|
||||
// Can't release Mutex while it is still locked, so scope the lock.
|
||||
{
|
||||
MutexAutoLock lock(Lock());
|
||||
|
||||
// |mWorkerPrivate| might not be safe to use anymore if we have already
|
||||
// cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first.
|
||||
if (mCleanedUp) {
|
||||
return;
|
||||
// |mWorkerPrivate| is not safe to use anymore if we have already
|
||||
// cleaned up and RemoveFeature(), so we need to check |mCleanedUp| first.
|
||||
if (CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
|
||||
|
||||
// Release the Promise and remove the PromiseWorkerProxy from the features of
|
||||
// the worker thread since the Promise has been resolved/rejected or the
|
||||
// worker thread has been cancelled.
|
||||
MOZ_ASSERT(mFeatureAdded);
|
||||
mWorkerPrivate->RemoveFeature(mWorkerPrivate->GetJSContext(), this);
|
||||
mFeatureAdded = false;
|
||||
CleanProperties();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mWorkerPrivate->GetJSContext() == aCx);
|
||||
|
||||
// Release the Promise and remove the PromiseWorkerProxy from the features of
|
||||
// the worker thread since the Promise has been resolved/rejected or the
|
||||
// worker thread has been cancelled.
|
||||
mWorkerPromise = nullptr;
|
||||
mWorkerPrivate->RemoveFeature(aCx, this);
|
||||
mCleanedUp = true;
|
||||
Release();
|
||||
}
|
||||
|
||||
// Specializations of MaybeRejectBrokenly we actually support.
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace workers {
|
||||
class WorkerPrivate;
|
||||
} // namespace workers
|
||||
|
||||
// A proxy to catch the resolved/rejected Promise's result from the main thread
|
||||
// and resolve/reject that on the worker thread eventually.
|
||||
// A proxy to (eventually) mirror a resolved/rejected Promise's result from the
|
||||
// main thread to a Promise on the worker thread.
|
||||
//
|
||||
// How to use:
|
||||
//
|
||||
@@ -36,13 +36,27 @@ class WorkerPrivate;
|
||||
// if (aRv.Failed()) {
|
||||
// return nullptr;
|
||||
// }
|
||||
// // Pass |promise| around to the WorkerMainThreadRunnable
|
||||
//
|
||||
// 2. Create a PromiseWorkerProxy wrapping the Promise. If this fails, the
|
||||
// worker is shutting down and you should fail the original call. This is
|
||||
// only likely to happen in (Gecko-specific) worker onclose handlers.
|
||||
//
|
||||
// nsRefPtr<PromiseWorkerProxy> proxy =
|
||||
// PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
// if (!proxy) {
|
||||
// // You may also reject the Promise with an AbortError or similar.
|
||||
// return nullptr;
|
||||
// }
|
||||
//
|
||||
// 3. Dispatch a runnable to the main thread, with a reference to the proxy to
|
||||
// perform the main thread operation. PromiseWorkerProxy is thread-safe
|
||||
// refcounted.
|
||||
//
|
||||
// 4. Return the worker thread promise to the JS caller:
|
||||
//
|
||||
// return promise.forget();
|
||||
//
|
||||
// 2. In your WorkerMainThreadRunnable's ctor, create a PromiseWorkerProxy
|
||||
// which holds a nsRefPtr<Promise> to the Promise created at #1.
|
||||
//
|
||||
// 3. In your WorkerMainThreadRunnable::MainThreadRun(), obtain a Promise on
|
||||
// 5. In your main thread runnable Run(), obtain a Promise on
|
||||
// the main thread and call its AppendNativeHandler(PromiseNativeHandler*)
|
||||
// to bind the PromiseWorkerProxy created at #2.
|
||||
//
|
||||
@@ -52,17 +66,49 @@ class WorkerPrivate;
|
||||
//
|
||||
// PromiseWorkerProxy can also be used in situations where there is no main
|
||||
// thread Promise, or where special handling is required on the worker thread
|
||||
// for promise resolution. Create a PromiseWorkerProxy as in steps 1 and
|
||||
// 2 above. When the main thread is ready to resolve the worker thread promise,
|
||||
// dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the
|
||||
// worker. This might be null! In the WorkerRunnable's WorkerRun() use
|
||||
// GetWorkerPromise() to access the Promise and resolve/reject it. Then call
|
||||
// CleanUp() on the worker thread.
|
||||
// for promise resolution. Create a PromiseWorkerProxy as in steps 1 to 3
|
||||
// above. When the main thread is ready to resolve the worker thread promise:
|
||||
//
|
||||
// IMPORTANT: Dispatching the runnable to the worker thread may fail causing
|
||||
// the promise to leak. To successfully release the promise on the
|
||||
// worker thread in this case, use |PromiseWorkerProxyControlRunnable| to
|
||||
// dispatch a control runnable that will deref the object on the correct thread.
|
||||
// 1. Acquire the mutex before attempting to access the worker private.
|
||||
//
|
||||
// AssertIsOnMainThread();
|
||||
// MutexAutoLock lock(proxy->Lock());
|
||||
// if (proxy->CleanedUp()) {
|
||||
// // Worker has already shut down, can't access worker private.
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// 2. Dispatch a runnable to the worker. Use GetWorkerPrivate() to acquire the
|
||||
// worker.
|
||||
//
|
||||
// nsRefPtr<FinishTaskWorkerRunnable> runnable =
|
||||
// new FinishTaskWorkerRunnable(proxy->GetWorkerPrivate(), proxy, result);
|
||||
// AutoJSAPI jsapi;
|
||||
// jsapi.Init();
|
||||
// if (!r->Dispatch(jsapi.cx())) {
|
||||
// // Worker is alive but not Running any more, so the Promise can't
|
||||
// // be resolved, give up. The proxy will get Release()d at some
|
||||
// // point.
|
||||
//
|
||||
// // Usually do nothing, but you may want to log the fact.
|
||||
// }
|
||||
//
|
||||
// 3. In the WorkerRunnable's WorkerRun() use WorkerPromise() to access the
|
||||
// Promise and resolve/reject it. Then call CleanUp().
|
||||
//
|
||||
// bool
|
||||
// WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
// {
|
||||
// aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
// nsRefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
// promise->MaybeResolve(mResult);
|
||||
// mProxy->CleanUp(aCx);
|
||||
// }
|
||||
//
|
||||
// Note: If a PromiseWorkerProxy is not cleaned up by a WorkerRunnable - this
|
||||
// can happen if the main thread Promise is never fulfilled - it will
|
||||
// stay alive till the worker reaches a Canceling state, even if all external
|
||||
// references to it are dropped.
|
||||
|
||||
class PromiseWorkerProxy : public PromiseNativeHandler,
|
||||
public workers::WorkerFeature
|
||||
@@ -77,20 +123,29 @@ public:
|
||||
Promise* aWorkerPromise,
|
||||
const JSStructuredCloneCallbacks* aCallbacks = nullptr);
|
||||
|
||||
// Main thread callers must hold Lock() and check CleanUp() before calling this.
|
||||
// Worker thread callers, this will assert that the proxy has not been cleaned
|
||||
// up.
|
||||
workers::WorkerPrivate* GetWorkerPrivate() const;
|
||||
|
||||
Promise* GetWorkerPromise() const;
|
||||
// This should only be used within WorkerRunnable::WorkerRun() running on the
|
||||
// worker thread! Do not call this after calling CleanUp().
|
||||
Promise* WorkerPromise() const;
|
||||
|
||||
void StoreISupports(nsISupports* aSupports);
|
||||
|
||||
// Worker thread only. Calling this invalidates several assumptions, so be
|
||||
// sure this is the last thing you do.
|
||||
// 1. WorkerPrivate() will no longer return a valid worker.
|
||||
// 2. WorkerPromise() will crash!
|
||||
void CleanUp(JSContext* aCx);
|
||||
|
||||
Mutex& GetCleanUpLock()
|
||||
Mutex& Lock()
|
||||
{
|
||||
return mCleanUpLock;
|
||||
}
|
||||
|
||||
bool IsClean() const
|
||||
bool CleanedUp() const
|
||||
{
|
||||
mCleanUpLock.AssertCurrentThreadOwns();
|
||||
return mCleanedUp;
|
||||
@@ -112,6 +167,11 @@ private:
|
||||
|
||||
virtual ~PromiseWorkerProxy();
|
||||
|
||||
bool AddRefObject();
|
||||
|
||||
// If not called from Create(), be sure to hold Lock().
|
||||
void CleanProperties();
|
||||
|
||||
// Function pointer for calling Promise::{ResolveInternal,RejectInternal}.
|
||||
typedef void (Promise::*RunCallbackFunc)(JSContext*,
|
||||
JS::Handle<JS::Value>);
|
||||
@@ -120,11 +180,15 @@ private:
|
||||
JS::Handle<JS::Value> aValue,
|
||||
RunCallbackFunc aFunc);
|
||||
|
||||
// Any thread with appropriate checks.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
// This lives on the worker thread.
|
||||
// Worker thread only.
|
||||
nsRefPtr<Promise> mWorkerPromise;
|
||||
|
||||
// Modified on the worker thread.
|
||||
// It is ok to *read* this without a lock on the worker.
|
||||
// Main thread must always acquire a lock.
|
||||
bool mCleanedUp; // To specify if the cleanUp() has been done.
|
||||
|
||||
const JSStructuredCloneCallbacks* mCallbacks;
|
||||
@@ -135,32 +199,10 @@ private:
|
||||
|
||||
// Ensure the worker and the main thread won't race to access |mCleanedUp|.
|
||||
Mutex mCleanUpLock;
|
||||
|
||||
// Maybe get rid of this entirely and rely on mCleanedUp
|
||||
DebugOnly<bool> mFeatureAdded;
|
||||
};
|
||||
|
||||
// Helper runnable used for releasing the proxied promise when the worker
|
||||
// is not accepting runnables and the promise object would leak.
|
||||
// See the instructions above.
|
||||
class PromiseWorkerProxyControlRunnable final : public workers::WorkerControlRunnable
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
|
||||
public:
|
||||
PromiseWorkerProxyControlRunnable(workers::WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aProxy)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount)
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, workers::WorkerPrivate* aWorkerPrivate) override;
|
||||
|
||||
private:
|
||||
~PromiseWorkerProxyControlRunnable()
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
|
||||
+32
-93
@@ -216,30 +216,6 @@ WorkerPushSubscription::Constructor(GlobalObject& aGlobal, const nsAString& aEnd
|
||||
return sub.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
// The caller MUST take ownership of the proxy's lock before it calls this.
|
||||
void
|
||||
ReleasePromiseWorkerProxy(already_AddRefed<PromiseWorkerProxy> aProxy)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = aProxy;
|
||||
MOZ_ASSERT(proxy);
|
||||
proxy->GetCleanUpLock().AssertCurrentThreadOwns();
|
||||
if (proxy->IsClean()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(proxy->GetWorkerPrivate(),
|
||||
proxy);
|
||||
|
||||
MOZ_ALWAYS_TRUE(cr->Dispatch(jsapi.cx()));
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class UnsubscribeResultRunnable final : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
@@ -260,15 +236,14 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
nsRefPtr<Promise> promise = proxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
promise->MaybeResolve(mSuccess);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NETWORK_ERR);
|
||||
}
|
||||
|
||||
proxy->CleanUp(aCx);
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
@@ -295,12 +270,12 @@ public:
|
||||
OnUnsubscribe(nsresult aStatus, bool aSuccess) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (!mProxy) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(mProxy, "OnUnsubscribe() called twice?");
|
||||
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (mProxy->IsClean()) {
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -308,29 +283,14 @@ public:
|
||||
jsapi.Init();
|
||||
|
||||
nsRefPtr<UnsubscribeResultRunnable> r =
|
||||
new UnsubscribeResultRunnable(mProxy, aStatus, aSuccess);
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
ReleasePromiseWorkerProxy(mProxy.forget());
|
||||
}
|
||||
|
||||
mProxy = nullptr;
|
||||
new UnsubscribeResultRunnable(proxy, aStatus, aSuccess);
|
||||
r->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~WorkerUnsubscribeResultCallback()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (mProxy) {
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (!mProxy->IsClean()) {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(mProxy->GetWorkerPrivate(), mProxy);
|
||||
cr->Dispatch(jsapi.cx());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
@@ -354,8 +314,8 @@ public:
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (mProxy->IsClean()) {
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -448,8 +408,7 @@ public:
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
nsRefPtr<Promise> promise = proxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
if (mEndpoint.IsEmpty()) {
|
||||
promise->MaybeResolve(JS::NullHandleValue);
|
||||
@@ -462,7 +421,7 @@ public:
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
proxy->CleanUp(aCx);
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
@@ -490,13 +449,12 @@ public:
|
||||
OnPushEndpoint(nsresult aStatus, const nsAString& aEndpoint) override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mProxy, "OnPushEndpoint() called twice?");
|
||||
|
||||
if (!mProxy) {
|
||||
return NS_OK;
|
||||
}
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (mProxy->IsClean()) {
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -504,30 +462,14 @@ public:
|
||||
jsapi.Init();
|
||||
|
||||
nsRefPtr<GetSubscriptionResultRunnable> r =
|
||||
new GetSubscriptionResultRunnable(mProxy, aStatus, aEndpoint, mScope);
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
ReleasePromiseWorkerProxy(mProxy.forget());
|
||||
}
|
||||
|
||||
mProxy = nullptr;
|
||||
new GetSubscriptionResultRunnable(proxy, aStatus, aEndpoint, mScope);
|
||||
r->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
~GetSubscriptionCallback()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
if (mProxy) {
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (!mProxy->IsClean()) {
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(mProxy->GetWorkerPrivate(), mProxy);
|
||||
cr->Dispatch(jsapi.cx());
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
private:
|
||||
nsRefPtr<PromiseWorkerProxy> mProxy;
|
||||
@@ -550,8 +492,8 @@ public:
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (mProxy->IsClean()) {
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -564,9 +506,11 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
|
||||
uint32_t permission = nsIPermissionManager::DENY_ACTION;
|
||||
nsresult rv = permManager->TestExactPermissionFromPrincipal(
|
||||
mProxy->GetWorkerPrivate()->GetPrincipal(),
|
||||
principal,
|
||||
"push",
|
||||
&permission);
|
||||
|
||||
@@ -582,9 +526,6 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = mProxy->GetWorkerPrivate()->GetPrincipal();
|
||||
mProxy = nullptr;
|
||||
|
||||
if (mAction == WorkerPushManager::SubscribeAction) {
|
||||
rv = client->Subscribe(mScope, principal, callback);
|
||||
} else {
|
||||
@@ -667,17 +608,17 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
|
||||
nsRefPtr<Promise> promise = proxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> promise = mProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
MOZ_ASSERT(uint32_t(mState) < ArrayLength(PushPermissionStateValues::strings));
|
||||
nsAutoCString stringState(PushPermissionStateValues::strings[uint32_t(mState)].value, PushPermissionStateValues::strings[uint32_t(mState)].length);
|
||||
nsAutoCString stringState(PushPermissionStateValues::strings[uint32_t(mState)].value,
|
||||
PushPermissionStateValues::strings[uint32_t(mState)].length);
|
||||
promise->MaybeResolve(NS_ConvertUTF8toUTF16(stringState));
|
||||
} else {
|
||||
promise->MaybeReject(aCx, JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
proxy->CleanUp(aCx);
|
||||
mProxy->CleanUp(aCx);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -701,8 +642,8 @@ public:
|
||||
Run() override
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mProxy->GetCleanUpLock());
|
||||
if (mProxy->IsClean()) {
|
||||
MutexAutoLock lock(mProxy->Lock());
|
||||
if (mProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -740,9 +681,7 @@ public:
|
||||
jsapi.Init();
|
||||
nsRefPtr<PermissionResultRunnable> r =
|
||||
new PermissionResultRunnable(mProxy, rv, state);
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
ReleasePromiseWorkerProxy(mProxy.forget());
|
||||
}
|
||||
r->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
Promise* promise = mPromiseProxy->WorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
nsTArray<nsRefPtr<ServiceWorkerClient>> ret;
|
||||
@@ -74,30 +74,24 @@ public:
|
||||
new ServiceWorkerWindowClient(promise->GetParentObject(),
|
||||
mValue.ElementAt(i))));
|
||||
}
|
||||
|
||||
promise->MaybeResolve(ret);
|
||||
|
||||
// release the reference on the worker thread.
|
||||
mPromiseProxy->CleanUp(aCx);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class MatchAllRunnable final : public nsRunnable
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
nsCString mScope;
|
||||
public:
|
||||
MatchAllRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aPromiseProxy,
|
||||
MatchAllRunnable(PromiseWorkerProxy* aPromiseProxy,
|
||||
const nsCString& aScope)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mPromiseProxy(aPromiseProxy),
|
||||
: mPromiseProxy(aPromiseProxy),
|
||||
mScope(aScope)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
@@ -105,33 +99,22 @@ public:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
// Don't resolve the promise if it was already released.
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
nsTArray<ServiceWorkerClientInfo> result;
|
||||
|
||||
swm->GetAllClients(mWorkerPrivate->GetPrincipal(), mScope, result);
|
||||
swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope, result);
|
||||
nsRefPtr<ResolvePromiseWorkerRunnable> r =
|
||||
new ResolvePromiseWorkerRunnable(mWorkerPrivate, mPromiseProxy, result);
|
||||
|
||||
AutoSafeJSContext cx;
|
||||
if (r->Dispatch(cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Dispatch to worker thread failed because the worker is shutting down.
|
||||
// Use a control runnable to release the runnable on the worker thread.
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> releaseRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(mWorkerPrivate, mPromiseProxy);
|
||||
|
||||
if (!releaseRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch MatchAll promise control runnable.");
|
||||
}
|
||||
new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
|
||||
mPromiseProxy, result);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
r->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@@ -158,7 +141,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
if (NS_SUCCEEDED(mResult)) {
|
||||
@@ -167,9 +150,7 @@ public:
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
// Release the reference on the worker thread.
|
||||
mPromiseProxy->CleanUp(aCx);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -178,14 +159,14 @@ class ClaimRunnable final : public nsRunnable
|
||||
{
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseProxy;
|
||||
nsCString mScope;
|
||||
// We grab the ID so we don't have to hold a lock the entire time the claim
|
||||
// operation is happening on the main thread.
|
||||
uint64_t mServiceWorkerID;
|
||||
|
||||
public:
|
||||
ClaimRunnable(PromiseWorkerProxy* aPromiseProxy, const nsCString& aScope)
|
||||
: mPromiseProxy(aPromiseProxy)
|
||||
, mScope(aScope)
|
||||
// Safe to call GetWorkerPrivate() since we are being called on the worker
|
||||
// thread via script (so no clean up has occured yet).
|
||||
, mServiceWorkerID(aPromiseProxy->GetWorkerPrivate()->ServiceWorkerID())
|
||||
{
|
||||
MOZ_ASSERT(aPromiseProxy);
|
||||
@@ -194,9 +175,8 @@ public:
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
// Don't resolve the promise if it was already released.
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -214,20 +194,7 @@ public:
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (r->Dispatch(cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Dispatch to worker thread failed because the worker is shutting down.
|
||||
// Use a control runnable to release the runnable on the worker thread.
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> releaseRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(workerPrivate, mPromiseProxy);
|
||||
|
||||
if (!releaseRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch Claim control runnable.");
|
||||
}
|
||||
|
||||
r->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@@ -257,21 +224,15 @@ ServiceWorkerClients::MatchAll(const ClientQueryOptions& aOptions,
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
if (!promiseProxy) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MatchAllRunnable> r =
|
||||
new MatchAllRunnable(workerPrivate,
|
||||
promiseProxy,
|
||||
new MatchAllRunnable(promiseProxy,
|
||||
NS_ConvertUTF16toUTF8(scope));
|
||||
nsresult rv = NS_DispatchToMainThread(r);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@@ -301,8 +262,8 @@ ServiceWorkerClients::Claim(ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
if (!promiseProxy) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@@ -312,10 +273,6 @@ ServiceWorkerClients::Claim(ErrorResult& aRv)
|
||||
nsRefPtr<ClaimRunnable> runnable =
|
||||
new ClaimRunnable(promiseProxy, NS_ConvertUTF16toUTF8(scope));
|
||||
|
||||
aRv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ public:
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
Promise* promise = mPromiseProxy->WorkerPromise();
|
||||
if (NS_SUCCEEDED(mStatus)) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
} else {
|
||||
@@ -318,7 +318,6 @@ class WorkerThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallbac
|
||||
|
||||
~WorkerThreadUpdateCallback()
|
||||
{
|
||||
Finish(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -351,8 +350,8 @@ public:
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mPromiseProxy.forget();
|
||||
|
||||
MutexAutoLock lock(proxy->GetCleanUpLock());
|
||||
if (proxy->IsClean()) {
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -361,11 +360,7 @@ public:
|
||||
|
||||
nsRefPtr<UpdateResultRunnable> r =
|
||||
new UpdateResultRunnable(proxy, aStatus);
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> r =
|
||||
new PromiseWorkerProxyControlRunnable(proxy->GetWorkerPrivate(), proxy);
|
||||
r->Dispatch(jsapi.cx());
|
||||
}
|
||||
r->Dispatch(jsapi.cx());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -384,8 +379,8 @@ public:
|
||||
AssertIsOnMainThread();
|
||||
ErrorResult result;
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -445,10 +440,9 @@ class FulfillUnregisterPromiseRunnable final : public WorkerRunnable
|
||||
nsRefPtr<PromiseWorkerProxy> mPromiseWorkerProxy;
|
||||
Maybe<bool> mState;
|
||||
public:
|
||||
FulfillUnregisterPromiseRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
PromiseWorkerProxy* aProxy,
|
||||
FulfillUnregisterPromiseRunnable(PromiseWorkerProxy* aProxy,
|
||||
Maybe<bool> aState)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
: WorkerRunnable(aProxy->GetWorkerPrivate(), WorkerThreadModifyBusyCount)
|
||||
, mPromiseWorkerProxy(aProxy)
|
||||
, mState(aState)
|
||||
{
|
||||
@@ -459,8 +453,7 @@ public:
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
Promise* promise = mPromiseWorkerProxy->GetWorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
nsRefPtr<Promise> promise = mPromiseWorkerProxy->WorkerPromise();
|
||||
if (mState.isSome()) {
|
||||
promise->MaybeResolve(mState.value());
|
||||
} else {
|
||||
@@ -481,6 +474,7 @@ public:
|
||||
explicit WorkerUnregisterCallback(PromiseWorkerProxy* aProxy)
|
||||
: mPromiseWorkerProxy(aProxy)
|
||||
{
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@@ -501,7 +495,7 @@ public:
|
||||
|
||||
private:
|
||||
~WorkerUnregisterCallback()
|
||||
{ }
|
||||
{}
|
||||
|
||||
void
|
||||
Finish(Maybe<bool> aState)
|
||||
@@ -511,24 +505,18 @@ private:
|
||||
return;
|
||||
}
|
||||
|
||||
MutexAutoLock lock(mPromiseWorkerProxy->GetCleanUpLock());
|
||||
if (mPromiseWorkerProxy->IsClean()) {
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = mPromiseWorkerProxy.forget();
|
||||
MutexAutoLock lock(proxy->Lock());
|
||||
if (proxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerRunnable> r =
|
||||
new FulfillUnregisterPromiseRunnable(mPromiseWorkerProxy->GetWorkerPrivate(),
|
||||
mPromiseWorkerProxy, aState);
|
||||
new FulfillUnregisterPromiseRunnable(proxy, aState);
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
if (!r->Dispatch(jsapi.cx())) {
|
||||
nsRefPtr<WorkerControlRunnable> cr =
|
||||
new PromiseWorkerProxyControlRunnable(
|
||||
mPromiseWorkerProxy->GetWorkerPrivate(),
|
||||
mPromiseWorkerProxy);
|
||||
cr->Dispatch(jsapi.cx());
|
||||
}
|
||||
r->Dispatch(jsapi.cx());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -544,12 +532,12 @@ class StartUnregisterRunnable final : public nsRunnable
|
||||
const nsString mScope;
|
||||
|
||||
public:
|
||||
StartUnregisterRunnable(WorkerPrivate* aWorker, Promise* aPromise,
|
||||
StartUnregisterRunnable(PromiseWorkerProxy* aProxy,
|
||||
const nsAString& aScope)
|
||||
: mPromiseWorkerProxy(PromiseWorkerProxy::Create(aWorker, aPromise))
|
||||
: mPromiseWorkerProxy(aProxy)
|
||||
, mScope(aScope)
|
||||
{
|
||||
// mPromiseWorkerProxy may be null if AddFeature failed.
|
||||
MOZ_ASSERT(aProxy);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
@@ -557,8 +545,6 @@ public:
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsRefPtr<WorkerUnregisterCallback> cb = new WorkerUnregisterCallback(mPromiseWorkerProxy);
|
||||
|
||||
// XXXnsm: There is a rare chance of this failing if the worker gets
|
||||
// destroyed. In that case, unregister() called from a SW is no longer
|
||||
// guaranteed to run. We should fix this by having a main thread proxy
|
||||
@@ -566,8 +552,8 @@ public:
|
||||
// principal. Can that be trusted?
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
{
|
||||
MutexAutoLock lock(mPromiseWorkerProxy->GetCleanUpLock());
|
||||
if (mPromiseWorkerProxy->IsClean()) {
|
||||
MutexAutoLock lock(mPromiseWorkerProxy->Lock());
|
||||
if (mPromiseWorkerProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -577,6 +563,8 @@ public:
|
||||
}
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
nsRefPtr<WorkerUnregisterCallback> cb =
|
||||
new WorkerUnregisterCallback(mPromiseWorkerProxy);
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm =
|
||||
mozilla::services::GetServiceWorkerManager();
|
||||
nsresult rv = swm->Unregister(principal, cb, mScope);
|
||||
@@ -962,8 +950,8 @@ ServiceWorkerRegistrationWorkerThread::Update(ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
|
||||
if (!proxy) {
|
||||
promise->MaybeResolve(NS_ERROR_DOM_ABORT_ERR);
|
||||
return promise.forget();
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<UpdateRunnable> r = new UpdateRunnable(proxy, mScope);
|
||||
@@ -992,7 +980,13 @@ ServiceWorkerRegistrationWorkerThread::Unregister(ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<StartUnregisterRunnable> r = new StartUnregisterRunnable(worker, promise, mScope);
|
||||
nsRefPtr<PromiseWorkerProxy> proxy = PromiseWorkerProxy::Create(worker, promise);
|
||||
if (!proxy) {
|
||||
aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<StartUnregisterRunnable> r = new StartUnregisterRunnable(proxy, mScope);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
|
||||
return promise.forget();
|
||||
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
nsRefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
if (mClientInfo) {
|
||||
@@ -80,7 +80,6 @@ public:
|
||||
, mPromiseProxy(aPromiseProxy)
|
||||
{
|
||||
MOZ_ASSERT(mPromiseProxy);
|
||||
MOZ_ASSERT(mPromiseProxy->GetWorkerPromise());
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
@@ -110,28 +109,18 @@ private:
|
||||
DispatchResult(UniquePtr<ServiceWorkerClientInfo>&& aClientInfo)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsRefPtr<ResolveOrRejectPromiseRunnable> resolveRunnable =
|
||||
new ResolveOrRejectPromiseRunnable(workerPrivate, mPromiseProxy,
|
||||
Move(aClientInfo));
|
||||
new ResolveOrRejectPromiseRunnable(mPromiseProxy->GetWorkerPrivate(),
|
||||
mPromiseProxy, Move(aClientInfo));
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (!resolveRunnable->Dispatch(cx)) {
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> controlRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(workerPrivate, mPromiseProxy);
|
||||
if (!controlRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch Focus promise control runnable.");
|
||||
}
|
||||
}
|
||||
resolveRunnable->Dispatch(jsapi.cx());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,17 +144,14 @@ ServiceWorkerWindowClient::Focus(ErrorResult& aRv) const
|
||||
if (workerPrivate->GlobalScope()->WindowInteractionAllowed()) {
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(workerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
return promise.forget();
|
||||
if (promiseProxy) {
|
||||
nsRefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId,
|
||||
promiseProxy);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
nsRefPtr<ClientFocusRunnable> r = new ClientFocusRunnable(mWindowId,
|
||||
promiseProxy);
|
||||
aRv = NS_DispatchToMainThread(r);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
promise->MaybeReject(aRv);
|
||||
}
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
}
|
||||
|
||||
@@ -546,9 +546,7 @@ public:
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
Promise* promise = mPromiseProxy->GetWorkerPromise();
|
||||
MOZ_ASSERT(promise);
|
||||
|
||||
nsRefPtr<Promise> promise = mPromiseProxy->WorkerPromise();
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
|
||||
// Release the reference on the worker thread.
|
||||
@@ -579,13 +577,12 @@ public:
|
||||
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
|
||||
MutexAutoLock lock(mPromiseProxy->GetCleanUpLock());
|
||||
if (mPromiseProxy->IsClean()) {
|
||||
MutexAutoLock lock(mPromiseProxy->Lock());
|
||||
if (mPromiseProxy->CleanedUp()) {
|
||||
return NS_OK;
|
||||
}
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
|
||||
swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope,
|
||||
workerPrivate->ServiceWorkerID());
|
||||
|
||||
@@ -594,20 +591,7 @@ public:
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
jsapi.Init();
|
||||
JSContext* cx = jsapi.cx();
|
||||
if (runnable->Dispatch(cx)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Dispatch to worker thread failed because the worker is shutting down.
|
||||
// Use a control runnable to release the runnable on the worker thread.
|
||||
nsRefPtr<PromiseWorkerProxyControlRunnable> releaseRunnable =
|
||||
new PromiseWorkerProxyControlRunnable(workerPrivate, mPromiseProxy);
|
||||
|
||||
if (!releaseRunnable->Dispatch(cx)) {
|
||||
NS_RUNTIMEABORT("Failed to dispatch Claim control runnable.");
|
||||
}
|
||||
|
||||
runnable->Dispatch(jsapi.cx());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@@ -627,8 +611,7 @@ ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv)
|
||||
|
||||
nsRefPtr<PromiseWorkerProxy> promiseProxy =
|
||||
PromiseWorkerProxy::Create(mWorkerPrivate, promise);
|
||||
if (!promiseProxy->GetWorkerPromise()) {
|
||||
// Don't dispatch if adding the worker feature failed.
|
||||
if (!promiseProxy) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
@@ -637,11 +620,7 @@ ServiceWorkerGlobalScope::SkipWaiting(ErrorResult& aRv)
|
||||
new WorkerScopeSkipWaitingRunnable(promiseProxy,
|
||||
NS_ConvertUTF16toUTF8(mScope));
|
||||
|
||||
aRv = NS_DispatchToMainThread(runnable);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* enum type for objects that can be allocated by an nsPresArena */
|
||||
|
||||
#ifndef mozilla_ArenaObjectID_h
|
||||
#define mozilla_ArenaObjectID_h
|
||||
|
||||
#include "nsQueryFrame.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum ArenaObjectID {
|
||||
eArenaObjectID_DummyBeforeFirstObjectID = nsQueryFrame::NON_FRAME_MARKER - 1,
|
||||
|
||||
#define PRES_ARENA_OBJECT(name_) \
|
||||
eArenaObjectID_##name_,
|
||||
#include "nsPresArenaObjectList.h"
|
||||
#undef PRES_ARENA_OBJECT
|
||||
|
||||
/**
|
||||
* The PresArena implementation uses this bit to distinguish objects
|
||||
* allocated by size from objects allocated by type ID (that is, frames
|
||||
* using AllocateByFrameID and other objects using AllocateByObjectID).
|
||||
* It should not collide with any Object ID (above) or frame ID (in
|
||||
* nsQueryFrame.h). It is not 0x80000000 to avoid the question of
|
||||
* whether enumeration constants are signed.
|
||||
*/
|
||||
eArenaObjectID_NON_OBJECT_MARKER = 0x40000000
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,167 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* smart pointer for strong references to nsPresArena-allocated objects
|
||||
that might be held onto until the arena's destruction */
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/nsRefPtr.h"
|
||||
|
||||
#ifndef mozilla_ArenaRefPtr_h
|
||||
#define mozilla_ArenaRefPtr_h
|
||||
|
||||
class nsPresArena;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* A class for holding strong references to nsPresArena-allocated
|
||||
* objects.
|
||||
*
|
||||
* Since the arena's lifetime is not related to the refcounts
|
||||
* of the objects allocated within it, it is possible to have a strong
|
||||
* reference to an arena-allocated object that lives until the
|
||||
* destruction of the arena. An ArenaRefPtr acts like a weak reference
|
||||
* in that it will clear its referent if the arena is about to go away.
|
||||
*
|
||||
* T must be a class that has these two methods:
|
||||
*
|
||||
* static mozilla::ArenaObjectID ArenaObjectID();
|
||||
* U* Arena();
|
||||
*
|
||||
* where U is a class that has these two methods:
|
||||
*
|
||||
* void RegisterArenaRefPtr(ArenaRefPtr<T>*);
|
||||
* void DeregisterArenaRefPtr(ArenaRefPtr<T>*);
|
||||
*
|
||||
* Currently, both nsPresArena and nsIPresShell can be used as U.
|
||||
*
|
||||
* The ArenaObjectID method must return the mozilla::ArenaObjectID that
|
||||
* uniquely identifies T, and the Arena method must return the nsPresArena
|
||||
* (or a proxy for it) in which the object was allocated.
|
||||
*/
|
||||
template<typename T>
|
||||
class ArenaRefPtr
|
||||
{
|
||||
friend class ::nsPresArena;
|
||||
|
||||
public:
|
||||
ArenaRefPtr()
|
||||
{
|
||||
AssertValidType();
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>& aRhs)
|
||||
{
|
||||
AssertValidType();
|
||||
assign(aRhs);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
MOZ_IMPLICIT ArenaRefPtr(already_AddRefed<I>&& aRhs)
|
||||
{
|
||||
AssertValidType();
|
||||
assign(aRhs);
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT ArenaRefPtr(T* aRhs)
|
||||
{
|
||||
AssertValidType();
|
||||
assign(aRhs);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
ArenaRefPtr<T>& operator=(already_AddRefed<I>& aRhs)
|
||||
{
|
||||
assign(aRhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
ArenaRefPtr<T>& operator=(already_AddRefed<I>&& aRhs)
|
||||
{
|
||||
assign(aRhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArenaRefPtr<T>& operator=(T* aRhs)
|
||||
{
|
||||
assign(aRhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ArenaRefPtr() { assign(nullptr); }
|
||||
|
||||
#ifdef MOZ_HAVE_REF_QUALIFIERS
|
||||
operator T*() const & { return get(); }
|
||||
operator T*() const && = delete;
|
||||
explicit operator bool() const { return !!mPtr; }
|
||||
bool operator!() const { return !mPtr; }
|
||||
#else
|
||||
operator T*() const { return get(); }
|
||||
#endif
|
||||
|
||||
T* operator->() const { return mPtr.operator->(); }
|
||||
T& operator*() const { return *get(); }
|
||||
|
||||
T* get() const { return mPtr; }
|
||||
|
||||
private:
|
||||
void AssertValidType();
|
||||
|
||||
/**
|
||||
* Clears the pointer to the arena-allocated object but skips the usual
|
||||
* step of deregistering the ArenaRefPtr from the nsPresArena. This
|
||||
* method is called by nsPresArena when clearing all registered ArenaRefPtrs
|
||||
* so that it can deregister them all at once, avoiding hash table churn.
|
||||
*/
|
||||
void ClearWithoutDeregistering()
|
||||
{
|
||||
mPtr = nullptr;
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
void assign(already_AddRefed<I>& aSmartPtr)
|
||||
{
|
||||
nsRefPtr<T> newPtr(aSmartPtr);
|
||||
assignFrom(newPtr);
|
||||
}
|
||||
|
||||
template<typename I>
|
||||
void assign(already_AddRefed<I>&& aSmartPtr)
|
||||
{
|
||||
nsRefPtr<T> newPtr(aSmartPtr);
|
||||
assignFrom(newPtr);
|
||||
}
|
||||
|
||||
void assign(T* aPtr) { assignFrom(aPtr); }
|
||||
|
||||
template<typename I>
|
||||
void assignFrom(I& aPtr)
|
||||
{
|
||||
if (aPtr == mPtr) {
|
||||
return;
|
||||
}
|
||||
bool sameArena = mPtr && aPtr && mPtr->Arena() == aPtr->Arena();
|
||||
if (mPtr && !sameArena) {
|
||||
MOZ_ASSERT(mPtr->Arena());
|
||||
mPtr->Arena()->DeregisterArenaRefPtr(this);
|
||||
}
|
||||
mPtr = Move(aPtr);
|
||||
if (mPtr && !sameArena) {
|
||||
MOZ_ASSERT(mPtr->Arena());
|
||||
mPtr->Arena()->RegisterArenaRefPtr(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<T> mPtr;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ArenaRefPtr_h
|
||||
@@ -0,0 +1,47 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
/* inline methods that belong in ArenaRefPtr.h, except that they require
|
||||
the inclusion of headers for all types that ArenaRefPtr can handle */
|
||||
|
||||
#ifndef mozilla_ArenaRefPtrInlines_h
|
||||
#define mozilla_ArenaRefPtrInlines_h
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsStyleStruct.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
ArenaRefPtr<T>::AssertValidType()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
bool ok =
|
||||
#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) \
|
||||
T::ArenaObjectID() == eArenaObjectID_##name_ ||
|
||||
#include "nsPresArenaObjectList.h"
|
||||
#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
false;
|
||||
MOZ_ASSERT(ok, "ArenaRefPtr<T> template parameter T must be declared in "
|
||||
"nsPresArenaObjectList with "
|
||||
"PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT");
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
nsPresArena::RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
|
||||
{
|
||||
MOZ_ASSERT(!mArenaRefPtrs.Contains(aPtr));
|
||||
mArenaRefPtrs.Put(aPtr, T::ArenaObjectID());
|
||||
}
|
||||
|
||||
#endif
|
||||
+827
-242
File diff suppressed because it is too large
Load Diff
+156
-18
@@ -49,6 +49,8 @@ private:
|
||||
{
|
||||
MOZ_ASSERT(!mReframingStyleContexts,
|
||||
"temporary member should be nulled out before destruction");
|
||||
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
|
||||
"leaving dangling pointers from AnimationsWithDestroyedFrame");
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -89,6 +91,10 @@ public:
|
||||
int32_t aModType,
|
||||
const nsAttrValue* aOldValue);
|
||||
|
||||
// Get an integer that increments every time we process pending restyles.
|
||||
// The value is never 0.
|
||||
uint32_t GetRestyleGeneration() const { return mRestyleGeneration; }
|
||||
|
||||
// Get an integer that increments every time there is a style change
|
||||
// as a result of a change to the :hover content state.
|
||||
uint32_t GetHoverGeneration() const { return mHoverGeneration; }
|
||||
@@ -127,6 +133,10 @@ public:
|
||||
*/
|
||||
nsresult ReparentStyleContext(nsIFrame* aFrame);
|
||||
|
||||
void ClearSelectors() {
|
||||
mPendingRestyles.ClearSelectors();
|
||||
}
|
||||
|
||||
private:
|
||||
// Used when restyling an element with a frame.
|
||||
void ComputeAndProcessStyleChange(nsIFrame* aFrame,
|
||||
@@ -243,6 +253,65 @@ public:
|
||||
nsStyleContext* aOldStyleContext,
|
||||
nsRefPtr<nsStyleContext>* aNewStyleContext /* inout */);
|
||||
|
||||
// AnimationsWithDestroyedFrame is used to stop animations 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:
|
||||
// Construct a AnimationsWithDestroyedFrame object. The caller must
|
||||
// ensure that aRestyleManager lives at least as long as the
|
||||
// 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.
|
||||
void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
|
||||
MOZ_ASSERT(aContent);
|
||||
nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
|
||||
if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
mContents.AppendElement(aContent);
|
||||
} else if (pseudoType == nsCSSPseudoElements::ePseudo_before) {
|
||||
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
|
||||
mBeforeContents.AppendElement(aContent->GetParent());
|
||||
} else if (pseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
|
||||
mAfterContents.AppendElement(aContent->GetParent());
|
||||
}
|
||||
}
|
||||
|
||||
void StopAnimationsForElementsWithoutFrames();
|
||||
|
||||
private:
|
||||
void StopAnimationsWithoutFrame(nsTArray<nsRefPtr<nsIContent>>& aArray,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
RestyleManager* mRestyleManager;
|
||||
AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
|
||||
|
||||
// Below three arrays might include elements that have already had their
|
||||
// animations stopped.
|
||||
//
|
||||
// mBeforeContents and mAfterContents hold the real element rather than
|
||||
// the content node for the generated content (which might change during
|
||||
// a reframe)
|
||||
nsTArray<nsRefPtr<nsIContent>> mContents;
|
||||
nsTArray<nsRefPtr<nsIContent>> mBeforeContents;
|
||||
nsTArray<nsRefPtr<nsIContent>> mAfterContents;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current AnimationsWithDestroyedFrame struct, or null if we're
|
||||
* not currently in a restyling operation.
|
||||
*/
|
||||
AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
|
||||
return mAnimationsWithDestroyedFrame;
|
||||
}
|
||||
|
||||
private:
|
||||
void RestyleForEmptyChange(Element* aContainer);
|
||||
|
||||
@@ -454,6 +523,12 @@ private:
|
||||
// Fast-path the common case (esp. for the animation restyle
|
||||
// tracker) of not having anything to do.
|
||||
if (aRestyleTracker.Count() || ShouldStartRebuildAllFor(aRestyleTracker)) {
|
||||
if (++mRestyleGeneration == 0) {
|
||||
// Keep mRestyleGeneration from being 0, since that's what
|
||||
// nsPresContext::GetRestyleGeneration returns when it no
|
||||
// longer has a RestyleManager.
|
||||
++mRestyleGeneration;
|
||||
}
|
||||
aRestyleTracker.DoProcessRestyles();
|
||||
}
|
||||
}
|
||||
@@ -474,6 +549,7 @@ private:
|
||||
bool mSkipAnimationRules : 1;
|
||||
bool mHavePendingNonAnimationRestyles : 1;
|
||||
|
||||
uint32_t mRestyleGeneration;
|
||||
uint32_t mHoverGeneration;
|
||||
nsChangeHint mRebuildAllExtraHint;
|
||||
nsRestyleHint mRebuildAllRestyleHint;
|
||||
@@ -487,6 +563,7 @@ private:
|
||||
uint64_t mAnimationGeneration;
|
||||
|
||||
ReframingStyleContexts* mReframingStyleContexts;
|
||||
AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame;
|
||||
|
||||
RestyleTracker mPendingRestyles;
|
||||
|
||||
@@ -616,9 +693,13 @@ private:
|
||||
// the work of the earlier values is also done.
|
||||
enum RestyleResult {
|
||||
|
||||
// do not restyle children
|
||||
// we left the old style context on the frame; do not restyle children
|
||||
eRestyleResult_Stop = 1,
|
||||
|
||||
// we got a new style context on this frame, but we know that children
|
||||
// do not depend on the changed values; do not restyle children
|
||||
eRestyleResult_StopWithStyleChange,
|
||||
|
||||
// continue restyling children
|
||||
eRestyleResult_Continue,
|
||||
|
||||
@@ -626,12 +707,20 @@ private:
|
||||
eRestyleResult_ContinueAndForceDescendants
|
||||
};
|
||||
|
||||
struct SwapInstruction
|
||||
{
|
||||
nsRefPtr<nsStyleContext> mOldContext;
|
||||
nsRefPtr<nsStyleContext> mNewContext;
|
||||
uint32_t mStructsToSwap;
|
||||
};
|
||||
|
||||
/**
|
||||
* First half of Restyle().
|
||||
*/
|
||||
RestyleResult RestyleSelf(nsIFrame* aSelf,
|
||||
nsRestyleHint aRestyleHint,
|
||||
uint32_t* aSwappedStructs);
|
||||
uint32_t* aSwappedStructs,
|
||||
nsTArray<SwapInstruction>& aSwaps);
|
||||
|
||||
/**
|
||||
* Restyle the children of this frame (and, in turn, their children).
|
||||
@@ -655,26 +744,47 @@ private:
|
||||
*/
|
||||
bool MustRestyleSelf(nsRestyleHint aRestyleHint, Element* aElement);
|
||||
|
||||
/**
|
||||
* Returns true iff aRestyleHint indicates that we can call
|
||||
* ReparentStyleContext rather than any other restyling method of
|
||||
* nsStyleSet that looks up a new rule node, and if we are
|
||||
* not in the process of reconstructing the whole rule tree.
|
||||
* This is used to check whether it is appropriate to call
|
||||
* ReparentStyleContext.
|
||||
*/
|
||||
bool CanReparentStyleContext(nsRestyleHint aRestyleHint);
|
||||
|
||||
/**
|
||||
* Helpers for Restyle().
|
||||
*/
|
||||
void AddLayerChangesForAnimation();
|
||||
|
||||
bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
|
||||
nsStyleContext* aOldContext,
|
||||
nsTArray<nsStyleContext*>& aContextsToMove);
|
||||
bool MoveStyleContextsForChildren(nsStyleContext* aOldContext);
|
||||
|
||||
/**
|
||||
* Helpers for RestyleSelf().
|
||||
*/
|
||||
void CaptureChange(nsStyleContext* aOldContext,
|
||||
nsStyleContext* aNewContext,
|
||||
nsChangeHint aChangeToAssume,
|
||||
uint32_t* aEqualStructs);
|
||||
RestyleResult ComputeRestyleResultFromFrame(nsIFrame* aSelf);
|
||||
RestyleResult ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
nsStyleContext* aNewContext);
|
||||
uint32_t* aEqualStructs,
|
||||
uint32_t* aSamePointerStructs);
|
||||
void ComputeRestyleResultFromFrame(nsIFrame* aSelf,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange);
|
||||
void ComputeRestyleResultFromNewContext(nsIFrame* aSelf,
|
||||
nsStyleContext* aNewContext,
|
||||
RestyleResult& aRestyleResult,
|
||||
bool& aCanStopWithStyleChange);
|
||||
|
||||
/**
|
||||
* Helpers for RestyleChildren().
|
||||
*/
|
||||
// Helpers for RestyleChildren().
|
||||
void RestyleUndisplayedDescendants(nsRestyleHint aChildRestyleHint);
|
||||
bool MustCheckUndisplayedContent(nsIFrame* aFrame,
|
||||
nsIContent*& aUndisplayedParent);
|
||||
|
||||
/**
|
||||
* In the following two methods, aParentStyleContext is either
|
||||
* mFrame->StyleContext() if we have a frame, or a display:contents
|
||||
@@ -689,15 +799,21 @@ private:
|
||||
nsStyleContext* aParentStyleContext,
|
||||
const uint8_t aDisplay);
|
||||
void MaybeReframeForBeforePseudo();
|
||||
void MaybeReframeForBeforePseudo(nsIFrame* aGenConParentFrame,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aStyleContext);
|
||||
void MaybeReframeForAfterPseudo(nsIFrame* aFrame);
|
||||
void MaybeReframeForAfterPseudo(nsIFrame* aGenConParentFrame,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aStyleContext);
|
||||
void MaybeReframeForPseudo(nsCSSPseudoElements::Type aPseudoType,
|
||||
nsIFrame* aGenConParentFrame,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aStyleContext);
|
||||
#ifdef DEBUG
|
||||
bool MustReframeForBeforePseudo();
|
||||
bool MustReframeForAfterPseudo(nsIFrame* aFrame);
|
||||
#endif
|
||||
bool MustReframeForPseudo(nsCSSPseudoElements::Type aPseudoType,
|
||||
nsIFrame* aGenConParentFrame,
|
||||
nsIFrame* aFrame,
|
||||
nsIContent* aContent,
|
||||
nsStyleContext* aStyleContext);
|
||||
void RestyleContentChildren(nsIFrame* aParent,
|
||||
nsRestyleHint aChildRestyleHint);
|
||||
void InitializeAccessibilityNotifications(nsStyleContext* aNewContext);
|
||||
@@ -715,7 +831,27 @@ private:
|
||||
eNotifyHidden
|
||||
};
|
||||
|
||||
void AddPendingRestylesForDescendantsMatchingSelectors(Element* aElement);
|
||||
// These methods handle the eRestyle_SomeDescendants hint by traversing
|
||||
// down the frame tree (and then when reaching undisplayed content,
|
||||
// the flattened content tree) find elements that match a selector
|
||||
// in mSelectorsForDescendants and call AddPendingRestyle for them.
|
||||
void ConditionallyRestyleChildren();
|
||||
void ConditionallyRestyleChildren(nsIFrame* aFrame,
|
||||
Element* aRestyleRoot);
|
||||
void ConditionallyRestyleContentChildren(nsIFrame* aFrame,
|
||||
Element* aRestyleRoot);
|
||||
void ConditionallyRestyleUndisplayedDescendants(nsIFrame* aFrame,
|
||||
Element* aRestyleRoot);
|
||||
void DoConditionallyRestyleUndisplayedDescendants(nsIContent* aParent,
|
||||
Element* aRestyleRoot);
|
||||
void ConditionallyRestyleUndisplayedNodes(UndisplayedNode* aUndisplayed,
|
||||
nsIContent* aUndisplayedParent,
|
||||
const uint8_t aDisplay,
|
||||
Element* aRestyleRoot);
|
||||
void ConditionallyRestyleContentDescendants(Element* aElement,
|
||||
Element* aRestyleRoot);
|
||||
bool ConditionallyRestyle(nsIFrame* aFrame, Element* aRestyleRoot);
|
||||
bool ConditionallyRestyle(Element* aElement, Element* aRestyleRoot);
|
||||
|
||||
#ifdef RESTYLE_LOGGING
|
||||
int32_t& LoggingDepth() { return mLoggingDepth; }
|
||||
@@ -755,6 +891,8 @@ private:
|
||||
// stay alive until the end of the restyle. (See comment in
|
||||
// ElementRestyler::Restyle.)
|
||||
nsTArray<nsRefPtr<nsStyleContext>>& mSwappedStructOwners;
|
||||
// Whether this is the root of the restyle.
|
||||
bool mIsRootOfRestyle;
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
const DesiredA11yNotifications mDesiredA11yNotifications;
|
||||
|
||||
@@ -162,7 +162,8 @@ CollectRestyles(nsISupports* aElement,
|
||||
// Unset the restyle bits now, so if they get readded later as we
|
||||
// process we won't clobber that adding of the bit.
|
||||
element->UnsetFlags(collector->tracker->RestyleBit() |
|
||||
collector->tracker->RootBit());
|
||||
collector->tracker->RootBit() |
|
||||
collector->tracker->ConditionalDescendantsBit());
|
||||
|
||||
RestyleEnumerateData** restyleArrayPtr = collector->restyleArrayPtr;
|
||||
RestyleEnumerateData* currentRestyle = *restyleArrayPtr;
|
||||
@@ -247,6 +248,12 @@ RestyleTracker::DoProcessRestyles()
|
||||
docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
}
|
||||
|
||||
// Create a AnimationsWithDestroyedFrame during restyling process to
|
||||
// stop animations on elements that have no frame at the end of the
|
||||
// restyling process.
|
||||
RestyleManager::AnimationsWithDestroyedFrame
|
||||
animationsWithDestroyedFrame(mRestyleManager);
|
||||
|
||||
// Create a ReframingStyleContexts struct on the stack and put it in our
|
||||
// mReframingStyleContexts for almost all of the remaining scope of
|
||||
// this function.
|
||||
@@ -446,6 +453,9 @@ RestyleTracker::DoProcessRestyles()
|
||||
}
|
||||
}
|
||||
|
||||
// mPendingRestyles is now empty.
|
||||
mHaveSelectors = false;
|
||||
|
||||
mRestyleManager->EndProcessingRestyles();
|
||||
}
|
||||
|
||||
@@ -511,4 +521,23 @@ RestyleTracker::AddRestyleRootsIfAwaitingRestyle(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RestyleTracker::ClearSelectors()
|
||||
{
|
||||
if (!mHaveSelectors) {
|
||||
return;
|
||||
}
|
||||
for (auto it = mPendingRestyles.Iter(); !it.Done(); it.Next()) {
|
||||
RestyleData* data = it.Data();
|
||||
if (data->mRestyleHint & eRestyle_SomeDescendants) {
|
||||
data->mRestyleHint =
|
||||
(data->mRestyleHint & ~eRestyle_SomeDescendants) | eRestyle_Subtree;
|
||||
data->mRestyleHintData.mSelectorsForDescendants.Clear();
|
||||
} else {
|
||||
MOZ_ASSERT(data->mRestyleHintData.mSelectorsForDescendants.IsEmpty());
|
||||
}
|
||||
}
|
||||
mHaveSelectors = false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
#include "mozilla/SplayTree.h"
|
||||
#include "mozilla/RestyleLogging.h"
|
||||
#include "GeckoProfiler.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
#include "ProfilerBacktrace.h"
|
||||
#endif
|
||||
|
||||
@@ -230,6 +231,7 @@ public:
|
||||
explicit RestyleTracker(Element::FlagsType aRestyleBits)
|
||||
: mRestyleBits(aRestyleBits)
|
||||
, mHaveLaterSiblingRestyles(false)
|
||||
, mHaveSelectors(false)
|
||||
{
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_ALL_RESTYLE_FLAGS) == 0,
|
||||
"Why do we have these bits set?");
|
||||
@@ -238,10 +240,10 @@ public:
|
||||
NS_PRECONDITION((mRestyleBits & ELEMENT_PENDING_RESTYLE_FLAGS) !=
|
||||
ELEMENT_PENDING_RESTYLE_FLAGS,
|
||||
"Shouldn't have both restyle flags set");
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS) != 0,
|
||||
NS_PRECONDITION((mRestyleBits & ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS) != 0,
|
||||
"Must have root flag");
|
||||
NS_PRECONDITION((mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS) !=
|
||||
(ELEMENT_ALL_RESTYLE_FLAGS & ~ELEMENT_PENDING_RESTYLE_FLAGS),
|
||||
NS_PRECONDITION((mRestyleBits & ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS) !=
|
||||
ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS,
|
||||
"Shouldn't have both root flags");
|
||||
}
|
||||
|
||||
@@ -256,10 +258,19 @@ public:
|
||||
/**
|
||||
* Add a restyle for the given element to the tracker. Returns true
|
||||
* if the element already had eRestyle_LaterSiblings set on it.
|
||||
*
|
||||
* aRestyleRoot is the closest restyle root for aElement. If the caller
|
||||
* does not know what the closest restyle root is, Nothing should be
|
||||
* passed. A Some(nullptr) restyle root can be passed if there is no
|
||||
* ancestor element that is a restyle root.
|
||||
*/
|
||||
bool AddPendingRestyle(Element* aElement, nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint,
|
||||
const RestyleHintData* aRestyleHintData = nullptr);
|
||||
const RestyleHintData* aRestyleHintData = nullptr,
|
||||
mozilla::Maybe<Element*> aRestyleRoot =
|
||||
mozilla::Nothing());
|
||||
|
||||
Element* FindClosestRestyleRoot(Element* aElement);
|
||||
|
||||
/**
|
||||
* Process the restyles we've been tracking.
|
||||
@@ -273,7 +284,13 @@ public:
|
||||
|
||||
// Return our ELEMENT_IS_POTENTIAL_(ANIMATION_)RESTYLE_ROOT bit
|
||||
Element::FlagsType RootBit() const {
|
||||
return mRestyleBits & ~ELEMENT_PENDING_RESTYLE_FLAGS;
|
||||
return mRestyleBits & ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS;
|
||||
}
|
||||
|
||||
// Return our ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR bit if present,
|
||||
// or 0 if it is not.
|
||||
Element::FlagsType ConditionalDescendantsBit() const {
|
||||
return mRestyleBits & ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR;
|
||||
}
|
||||
|
||||
struct Hints {
|
||||
@@ -302,7 +319,7 @@ public:
|
||||
// that we called AddPendingRestyle for and found the element this is
|
||||
// the RestyleData for as its nearest restyle root.
|
||||
nsTArray<nsRefPtr<Element>> mDescendants;
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS)
|
||||
#if defined(MOZ_ENABLE_PROFILER_SPS) && !defined(MOZILLA_XPCOMRT_API)
|
||||
UniquePtr<ProfilerBacktrace> mBacktrace;
|
||||
#endif
|
||||
};
|
||||
@@ -342,6 +359,14 @@ public:
|
||||
void AddRestyleRootsIfAwaitingRestyle(
|
||||
const nsTArray<nsRefPtr<Element>>& aElements);
|
||||
|
||||
/**
|
||||
* Converts any eRestyle_SomeDescendants restyle hints in the pending restyle
|
||||
* table into eRestyle_Subtree hints and clears out the associated arrays of
|
||||
* nsCSSSelector pointers. This is called in response to a style sheet change
|
||||
* that might have cause an nsCSSSelector to be destroyed.
|
||||
*/
|
||||
void ClearSelectors();
|
||||
|
||||
/**
|
||||
* The document we're associated with.
|
||||
*/
|
||||
@@ -371,8 +396,9 @@ private:
|
||||
typedef nsClassHashtable<nsISupportsHashKey, RestyleData> PendingRestyleTable;
|
||||
typedef nsAutoTArray< nsRefPtr<Element>, 32> RestyleRootArray;
|
||||
// Our restyle bits. These will be a subset of ELEMENT_ALL_RESTYLE_FLAGS, and
|
||||
// will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS and one flag
|
||||
// that's not in ELEMENT_PENDING_RESTYLE_FLAGS.
|
||||
// will include one flag from ELEMENT_PENDING_RESTYLE_FLAGS, one flag
|
||||
// from ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS, and might also include
|
||||
// ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR.
|
||||
Element::FlagsType mRestyleBits;
|
||||
RestyleManager* mRestyleManager; // Owns us
|
||||
// A hashtable that maps elements to pointers to RestyleData structs. The
|
||||
@@ -392,6 +418,9 @@ private:
|
||||
// flag. We need this to avoid enumerating the hashtable looking
|
||||
// for such entries when we can't possibly have any.
|
||||
bool mHaveLaterSiblingRestyles;
|
||||
// True if we have some entries with selectors in the restyle hint data.
|
||||
// We use this to skip iterating over mPendingRestyles in ClearSelectors.
|
||||
bool mHaveSelectors;
|
||||
};
|
||||
|
||||
inline bool
|
||||
@@ -402,6 +431,11 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
{
|
||||
RestyleData* existingData;
|
||||
|
||||
if (aRestyleHintData &&
|
||||
!aRestyleHintData->mSelectorsForDescendants.IsEmpty()) {
|
||||
mHaveSelectors = true;
|
||||
}
|
||||
|
||||
// Check the RestyleBit() flag before doing the hashtable Get, since
|
||||
// it's possible that the data in the hashtable isn't actually
|
||||
// relevant anymore (if the flag is not set).
|
||||
@@ -412,6 +446,13 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
existingData = nullptr;
|
||||
}
|
||||
|
||||
if (aRestyleHint & eRestyle_SomeDescendants) {
|
||||
NS_ASSERTION(ConditionalDescendantsBit(),
|
||||
"why are we getting eRestyle_SomeDescendants in an "
|
||||
"animation-only restyle?");
|
||||
aElement->SetFlags(ConditionalDescendantsBit());
|
||||
}
|
||||
|
||||
if (!existingData) {
|
||||
RestyleData* rd =
|
||||
new RestyleData(aRestyleHint, aMinChangeHint, aRestyleHintData);
|
||||
@@ -437,11 +478,40 @@ RestyleTracker::AddPendingRestyleToTable(Element* aElement,
|
||||
return hadRestyleLaterSiblings;
|
||||
}
|
||||
|
||||
inline mozilla::dom::Element*
|
||||
RestyleTracker::FindClosestRestyleRoot(Element* aElement)
|
||||
{
|
||||
Element* cur = aElement;
|
||||
while (!cur->HasFlag(RootBit())) {
|
||||
nsIContent* parent = cur->GetFlattenedTreeParent();
|
||||
// Stop if we have no parent or the parent is not an element or
|
||||
// we're part of the viewport scrollbars (because those are not
|
||||
// frametree descendants of the primary frame of the root
|
||||
// element).
|
||||
// XXXbz maybe the primary frame of the root should be the root scrollframe?
|
||||
if (!parent || !parent->IsElement() ||
|
||||
// If we've hit the root via a native anonymous kid and that
|
||||
// this native anonymous kid is not obviously a descendant
|
||||
// of the root's primary frame, assume we're under the root
|
||||
// scrollbars. Since those don't get reresolved when
|
||||
// reresolving the root, we need to make sure to add the
|
||||
// element to mRestyleRoots.
|
||||
(cur->IsInNativeAnonymousSubtree() && !parent->GetParent() &&
|
||||
cur->GetPrimaryFrame() &&
|
||||
cur->GetPrimaryFrame()->GetParent() != parent->GetPrimaryFrame())) {
|
||||
return nullptr;
|
||||
}
|
||||
cur = parent->AsElement();
|
||||
}
|
||||
return cur;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RestyleTracker::AddPendingRestyle(Element* aElement,
|
||||
nsRestyleHint aRestyleHint,
|
||||
nsChangeHint aMinChangeHint,
|
||||
const RestyleHintData* aRestyleHintData)
|
||||
const RestyleHintData* aRestyleHintData,
|
||||
mozilla::Maybe<Element*> aRestyleRoot)
|
||||
{
|
||||
bool hadRestyleLaterSiblings =
|
||||
AddPendingRestyleToTable(aElement, aRestyleHint, aMinChangeHint,
|
||||
@@ -452,29 +522,11 @@ RestyleTracker::AddPendingRestyle(Element* aElement,
|
||||
// ReResolveStyleContext on it or just reframe it).
|
||||
if ((aRestyleHint & ~eRestyle_LaterSiblings) ||
|
||||
(aMinChangeHint & nsChangeHint_ReconstructFrame)) {
|
||||
Element* cur = aElement;
|
||||
while (!cur->HasFlag(RootBit())) {
|
||||
nsIContent* parent = cur->GetFlattenedTreeParent();
|
||||
// Stop if we have no parent or the parent is not an element or
|
||||
// we're part of the viewport scrollbars (because those are not
|
||||
// frametree descendants of the primary frame of the root
|
||||
// element).
|
||||
// XXXbz maybe the primary frame of the root should be the root scrollframe?
|
||||
if (!parent || !parent->IsElement() ||
|
||||
// If we've hit the root via a native anonymous kid and that
|
||||
// this native anonymous kid is not obviously a descendant
|
||||
// of the root's primary frame, assume we're under the root
|
||||
// scrollbars. Since those don't get reresolved when
|
||||
// reresolving the root, we need to make sure to add the
|
||||
// element to mRestyleRoots.
|
||||
(cur->IsInNativeAnonymousSubtree() && !parent->GetParent() &&
|
||||
cur->GetPrimaryFrame() &&
|
||||
cur->GetPrimaryFrame()->GetParent() != parent->GetPrimaryFrame())) {
|
||||
mRestyleRoots.AppendElement(aElement);
|
||||
cur = aElement;
|
||||
break;
|
||||
}
|
||||
cur = parent->AsElement();
|
||||
Element* cur =
|
||||
aRestyleRoot ? *aRestyleRoot : FindClosestRestyleRoot(aElement);
|
||||
if (!cur) {
|
||||
mRestyleRoots.AppendElement(aElement);
|
||||
cur = aElement;
|
||||
}
|
||||
// At this point some ancestor of aElement (possibly aElement
|
||||
// itself) is in mRestyleRoots. Set the root bit on aElement, to
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.style.display = "contents";
|
||||
document.designMode = 'on';
|
||||
document.documentElement.insertAdjacentHTML("beforeEnd", "<span><optgroup>");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
||||
@@ -460,4 +460,5 @@ load 1061028.html
|
||||
load 1116104.html
|
||||
load 1107508-1.html
|
||||
load 1127198-1.html
|
||||
load 1140198.html
|
||||
load 1297835.html
|
||||
|
||||
@@ -82,6 +82,7 @@ EXPORTS += [
|
||||
'nsIReflowCallback.h',
|
||||
'nsLayoutUtils.h',
|
||||
'nsPresArena.h',
|
||||
'nsPresArenaObjectList.h',
|
||||
'nsPresContext.h',
|
||||
'nsPresState.h',
|
||||
'nsRefreshDriver.h',
|
||||
@@ -94,6 +95,9 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'ArenaObjectID.h',
|
||||
'ArenaRefPtr.h',
|
||||
'ArenaRefPtrInlines.h',
|
||||
'GeometryUtils.h',
|
||||
'PaintTracker.h',
|
||||
'RestyleLogging.h',
|
||||
|
||||
@@ -2606,8 +2606,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
|
||||
newFrame = frameItems.FirstChild();
|
||||
NS_ASSERTION(frameItems.OnlyChild(), "multiple root element frames");
|
||||
} else {
|
||||
MOZ_ASSERT(display->mDisplay == NS_STYLE_DISPLAY_BLOCK ||
|
||||
display->mDisplay == NS_STYLE_DISPLAY_CONTENTS,
|
||||
MOZ_ASSERT(display->mDisplay == NS_STYLE_DISPLAY_BLOCK,
|
||||
"Unhandled display type for root element");
|
||||
contentFrame = NS_NewBlockFormattingContext(mPresShell, styleContext);
|
||||
nsFrameItems frameItems;
|
||||
|
||||
@@ -217,8 +217,8 @@ nsCaret::ComputeMetrics(nsIFrame* aFrame, int32_t aOffset, nscoord aCaretHeight)
|
||||
// between 0 and 1 goes up to 1 so we don't let the caret disappear.
|
||||
int32_t tpp = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
Metrics result;
|
||||
result.mCaretWidth = NS_ROUND_CARET_TO_PIXELS(caretWidth, tpp);
|
||||
result.mBidiIndicatorSize = NS_ROUND_CARET_TO_PIXELS(bidiIndicatorSize, tpp);
|
||||
result.mCaretWidth = NS_ROUND_BORDER_TO_PIXELS(caretWidth, tpp);
|
||||
result.mBidiIndicatorSize = NS_ROUND_BORDER_TO_PIXELS(bidiIndicatorSize, tpp);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -616,7 +616,7 @@ NS_IMETHODIMP
|
||||
nsCaret::NotifySelectionChanged(nsIDOMDocument *, nsISelection *aDomSel,
|
||||
int16_t aReason)
|
||||
{
|
||||
if (aReason & nsISelectionListener::MOUSEUP_REASON)//this wont do
|
||||
if ((aReason & nsISelectionListener::MOUSEUP_REASON) || !IsVisible())//this wont do
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsISelection> domSel(do_QueryReferent(mDomSelectionWeak));
|
||||
|
||||
@@ -129,7 +129,7 @@ enum nsChangeHint {
|
||||
* has changed whether the frame is a container for fixed-pos or abs-pos
|
||||
* elements, but reframing is otherwise not needed.
|
||||
*/
|
||||
nsChangeHint_AddOrRemoveTransform = 0x20000,
|
||||
nsChangeHint_UpdateContainingBlock = 0x20000,
|
||||
|
||||
/**
|
||||
* This change hint has *no* change handling behavior. However, it
|
||||
@@ -287,7 +287,7 @@ inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight)
|
||||
nsChangeHint_UpdateParentOverflow | \
|
||||
nsChangeHint_ChildrenOnlyTransform | \
|
||||
nsChangeHint_RecomputePosition | \
|
||||
nsChangeHint_AddOrRemoveTransform | \
|
||||
nsChangeHint_UpdateContainingBlock | \
|
||||
nsChangeHint_BorderStyleNoneChange | \
|
||||
nsChangeHint_NeedReflow | \
|
||||
nsChangeHint_ReflowChangesSizeOrPosition | \
|
||||
@@ -305,7 +305,7 @@ inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint)
|
||||
nsChangeHint_UpdateParentOverflow |
|
||||
nsChangeHint_ChildrenOnlyTransform |
|
||||
nsChangeHint_RecomputePosition |
|
||||
nsChangeHint_AddOrRemoveTransform |
|
||||
nsChangeHint_UpdateContainingBlock |
|
||||
nsChangeHint_BorderStyleNoneChange |
|
||||
nsChangeHint_UpdateComputedBSize));
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef nsIPresShell_h___
|
||||
#define nsIPresShell_h___
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
@@ -246,7 +247,7 @@ public:
|
||||
* the same aSize value. AllocateByObjectID returns zero-filled memory.
|
||||
* AllocateByObjectID is infallible and will abort on out-of-memory.
|
||||
*/
|
||||
void* AllocateByObjectID(nsPresArena::ObjectID aID, size_t aSize)
|
||||
void* AllocateByObjectID(mozilla::ArenaObjectID aID, size_t aSize)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mPresArenaAllocCount++;
|
||||
@@ -256,7 +257,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void FreeByObjectID(nsPresArena::ObjectID aID, void* aPtr)
|
||||
void FreeByObjectID(mozilla::ArenaObjectID aID, void* aPtr)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
mPresArenaAllocCount--;
|
||||
@@ -291,6 +292,23 @@ public:
|
||||
mFrameArena.FreeBySize(aSize, aPtr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
|
||||
{
|
||||
mFrameArena.RegisterArenaRefPtr(aPtr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DeregisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
|
||||
{
|
||||
mFrameArena.DeregisterArenaRefPtr(aPtr);
|
||||
}
|
||||
|
||||
void ClearArenaRefPtrs(mozilla::ArenaObjectID aObjectID)
|
||||
{
|
||||
mFrameArena.ClearArenaRefPtrs(aObjectID);
|
||||
}
|
||||
|
||||
nsIDocument* GetDocument() const { return mDocument; }
|
||||
|
||||
nsPresContext* GetPresContext() const { return mPresContext; }
|
||||
@@ -507,9 +525,19 @@ public:
|
||||
eTreeChange, // mark intrinsic widths dirty on aFrame and its ancestors
|
||||
eStyleChange // Do eTreeChange, plus all of aFrame's descendants
|
||||
};
|
||||
enum ReflowRootHandling {
|
||||
ePositionOrSizeChange, // aFrame is changing position or size
|
||||
eNoPositionOrSizeChange, // ... NOT changing ...
|
||||
eInferFromBitToAdd // is changing iff (aBitToAdd == NS_FRAME_IS_DIRTY)
|
||||
|
||||
// Note: With eStyleChange, these can also apply to out-of-flows
|
||||
// in addition to aFrame.
|
||||
};
|
||||
virtual void FrameNeedsReflow(nsIFrame *aFrame,
|
||||
IntrinsicDirty aIntrinsicDirty,
|
||||
nsFrameState aBitToAdd) = 0;
|
||||
nsFrameState aBitToAdd,
|
||||
ReflowRootHandling aRootHandling =
|
||||
eInferFromBitToAdd) = 0;
|
||||
|
||||
/**
|
||||
* Calls FrameNeedsReflow on all fixed position children of the root frame.
|
||||
|
||||
@@ -23,9 +23,12 @@
|
||||
#include "nsDebug.h"
|
||||
#include "nsArenaMemoryStats.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsStyleContext.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// Size to use for PLArena block allocations.
|
||||
static const size_t ARENA_PAGE_SIZE = 8192;
|
||||
|
||||
@@ -36,6 +39,8 @@ nsPresArena::nsPresArena()
|
||||
|
||||
nsPresArena::~nsPresArena()
|
||||
{
|
||||
ClearArenaRefPtrs();
|
||||
|
||||
#if defined(MOZ_HAVE_MEM_CHECKS)
|
||||
for (auto iter = mFreeLists.Iter(); !iter.Done(); iter.Next()) {
|
||||
FreeList* entry = iter.Get();
|
||||
@@ -47,9 +52,62 @@ nsPresArena::~nsPresArena()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
PL_FinishArenaPool(&mPool);
|
||||
}
|
||||
|
||||
/* inline */ void
|
||||
nsPresArena::ClearArenaRefPtrWithoutDeregistering(void* aPtr,
|
||||
ArenaObjectID aObjectID)
|
||||
{
|
||||
switch (aObjectID) {
|
||||
#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) \
|
||||
case eArenaObjectID_##name_: \
|
||||
static_cast<ArenaRefPtr<name_>*>(aPtr)->ClearWithoutDeregistering(); \
|
||||
return;
|
||||
#include "nsPresArenaObjectList.h"
|
||||
#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (aObjectID) {
|
||||
#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) \
|
||||
case eArenaObjectID_##name_: \
|
||||
MOZ_ASSERT(false, #name_ " must be declared in nsPresArenaObjectList.h "\
|
||||
"with PRES_ARENA_OBJECT_SUPPORTS_ARENAREFPTR"); \
|
||||
break;
|
||||
#include "nsPresArenaObjectList.h"
|
||||
#undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
default:
|
||||
MOZ_ASSERT(false, "unexpected ArenaObjectID value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsPresArena::ClearArenaRefPtrs()
|
||||
{
|
||||
for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
|
||||
void* ptr = iter.Key();
|
||||
ArenaObjectID id = iter.UserData();
|
||||
ClearArenaRefPtrWithoutDeregistering(ptr, id);
|
||||
}
|
||||
mArenaRefPtrs.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
nsPresArena::ClearArenaRefPtrs(ArenaObjectID aObjectID)
|
||||
{
|
||||
for (auto iter = mArenaRefPtrs.Iter(); !iter.Done(); iter.Next()) {
|
||||
void* ptr = iter.Key();
|
||||
ArenaObjectID id = iter.UserData();
|
||||
if (id == aObjectID) {
|
||||
ClearArenaRefPtrWithoutDeregistering(ptr, id);
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
nsPresArena::Allocate(uint32_t aCode, size_t aSize)
|
||||
{
|
||||
@@ -170,17 +228,17 @@ nsPresArena::AddSizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf,
|
||||
break;
|
||||
#include "nsFrameIdList.h"
|
||||
#undef FRAME_ID
|
||||
case nsLineBox_id:
|
||||
case eArenaObjectID_nsLineBox:
|
||||
p = &aArenaStats->mLineBoxes;
|
||||
break;
|
||||
case nsRuleNode_id:
|
||||
case eArenaObjectID_nsRuleNode:
|
||||
p = &aArenaStats->mRuleNodes;
|
||||
break;
|
||||
case nsStyleContext_id:
|
||||
case eArenaObjectID_nsStyleContext:
|
||||
p = &aArenaStats->mStyleContexts;
|
||||
break;
|
||||
#define STYLE_STRUCT(name_, checkdata_cb_) \
|
||||
case nsStyle##name_##_id:
|
||||
case eArenaObjectID_nsStyle##name_:
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
p = &aArenaStats->mStyleStructs;
|
||||
|
||||
+54
-40
@@ -10,11 +10,14 @@
|
||||
#ifndef nsPresArena_h___
|
||||
#define nsPresArena_h___
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "mozilla/ArenaRefPtr.h"
|
||||
#include "mozilla/MemoryChecking.h" // Note: Do not remove this, needed for MOZ_HAVE_MEM_CHECKS below
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include <stdint.h>
|
||||
#include "nscore.h"
|
||||
#include "nsQueryFrame.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include "plarena.h"
|
||||
@@ -26,51 +29,18 @@ public:
|
||||
nsPresArena();
|
||||
~nsPresArena();
|
||||
|
||||
enum ObjectID {
|
||||
nsLineBox_id = nsQueryFrame::NON_FRAME_MARKER,
|
||||
nsRuleNode_id,
|
||||
nsStyleContext_id,
|
||||
nsInheritedStyleData_id,
|
||||
nsResetStyleData_id,
|
||||
nsConditionalResetStyleData_id,
|
||||
nsConditionalResetStyleDataEntry_id,
|
||||
nsFrameList_id,
|
||||
|
||||
CustomCounterStyle_id,
|
||||
DependentBuiltinCounterStyle_id,
|
||||
|
||||
First_nsStyleStruct_id,
|
||||
DummyBeforeStyleStructs_id = First_nsStyleStruct_id - 1,
|
||||
|
||||
#define STYLE_STRUCT(name_, checkdata_cb_) \
|
||||
nsStyle##name_##_id,
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
||||
DummyAfterStyleStructs_id,
|
||||
Last_nsStyleStruct_id = DummyAfterStyleStructs_id - 1,
|
||||
|
||||
/**
|
||||
* The PresArena implementation uses this bit to distinguish objects
|
||||
* allocated by size from objects allocated by type ID (that is, frames
|
||||
* using AllocateByFrameID and other objects using AllocateByObjectID).
|
||||
* It should not collide with any Object ID (above) or frame ID (in
|
||||
* nsQueryFrame.h). It is not 0x80000000 to avoid the question of
|
||||
* whether enumeration constants are signed.
|
||||
*/
|
||||
NON_OBJECT_MARKER = 0x40000000
|
||||
};
|
||||
|
||||
/**
|
||||
* Pool allocation with recycler lists indexed by object size, aSize.
|
||||
*/
|
||||
void* AllocateBySize(size_t aSize)
|
||||
{
|
||||
return Allocate(uint32_t(aSize) | uint32_t(NON_OBJECT_MARKER), aSize);
|
||||
return Allocate(uint32_t(aSize) |
|
||||
uint32_t(mozilla::eArenaObjectID_NON_OBJECT_MARKER), aSize);
|
||||
}
|
||||
void FreeBySize(size_t aSize, void* aPtr)
|
||||
{
|
||||
Free(uint32_t(aSize) | uint32_t(NON_OBJECT_MARKER), aPtr);
|
||||
Free(uint32_t(aSize) |
|
||||
uint32_t(mozilla::eArenaObjectID_NON_OBJECT_MARKER), aPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,15 +60,54 @@ public:
|
||||
* Pool allocation with recycler lists indexed by object-type ID (see above).
|
||||
* Every aID must always be used with the same object size, aSize.
|
||||
*/
|
||||
void* AllocateByObjectID(ObjectID aID, size_t aSize)
|
||||
void* AllocateByObjectID(mozilla::ArenaObjectID aID, size_t aSize)
|
||||
{
|
||||
return Allocate(aID, aSize);
|
||||
}
|
||||
void FreeByObjectID(ObjectID aID, void* aPtr)
|
||||
void FreeByObjectID(mozilla::ArenaObjectID aID, void* aPtr)
|
||||
{
|
||||
Free(aID, aPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an ArenaRefPtr to be cleared when this arena is about to
|
||||
* be destroyed.
|
||||
*
|
||||
* (Defined in ArenaRefPtrInlines.h.)
|
||||
*
|
||||
* @param aPtr The ArenaRefPtr to clear.
|
||||
* @param aObjectID The ArenaObjectID value that uniquely identifies
|
||||
* the type of object the ArenaRefPtr holds.
|
||||
*/
|
||||
template<typename T>
|
||||
void RegisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr);
|
||||
|
||||
/**
|
||||
* Deregister an ArenaRefPtr that was previously registered with
|
||||
* RegisterArenaRefPtr.
|
||||
*/
|
||||
template<typename T>
|
||||
void DeregisterArenaRefPtr(mozilla::ArenaRefPtr<T>* aPtr)
|
||||
{
|
||||
MOZ_ASSERT(mArenaRefPtrs.Contains(aPtr));
|
||||
mArenaRefPtrs.Remove(aPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all currently registered ArenaRefPtrs. This will be called during
|
||||
* the destructor, but can be called by users of nsPresArena who want to
|
||||
* ensure arena-allocated objects are released earlier.
|
||||
*/
|
||||
void ClearArenaRefPtrs();
|
||||
|
||||
/**
|
||||
* Clears all currently registered ArenaRefPtrs for the given ArenaObjectID.
|
||||
* This is called when we reconstruct the rule tree so that style contexts
|
||||
* pointing into the old rule tree aren't released afterwards, triggering an
|
||||
* assertion in ~nsStyleContext.
|
||||
*/
|
||||
void ClearArenaRefPtrs(mozilla::ArenaObjectID aObjectID);
|
||||
|
||||
/**
|
||||
* Increment aArenaStats with sizes of interesting objects allocated in this
|
||||
* arena and its mOther field with the size of everything else.
|
||||
@@ -110,6 +119,10 @@ private:
|
||||
void* Allocate(uint32_t aCode, size_t aSize);
|
||||
void Free(uint32_t aCode, void* aPtr);
|
||||
|
||||
inline void ClearArenaRefPtrWithoutDeregistering(
|
||||
void* aPtr,
|
||||
mozilla::ArenaObjectID aObjectID);
|
||||
|
||||
// All keys to this hash table fit in 32 bits (see below) so we do not
|
||||
// bother actually hashing them.
|
||||
class FreeList : public PLDHashEntryHdr
|
||||
@@ -144,6 +157,7 @@ private:
|
||||
|
||||
nsTHashtable<FreeList> mFreeLists;
|
||||
PLArenaPool mPool;
|
||||
nsDataHashtable<nsPtrHashKey<void>, mozilla::ArenaObjectID> mArenaRefPtrs;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* a list of all types that can be allocated in an nsPresArena, for
|
||||
preprocessing */
|
||||
|
||||
#ifdef STYLE_STRUCT
|
||||
#error Sorry nsPresArenaObjectList.h needs to use STYLE_STRUCT!
|
||||
#endif
|
||||
|
||||
#ifdef PRES_ARENA_OBJECT
|
||||
#if defined(PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT) || \
|
||||
defined(PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT)
|
||||
#error Must not define PRES_ARENA_OBJECT along with \
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT or \
|
||||
PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT.
|
||||
#endif
|
||||
#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) PRES_ARENA_OBJECT(name_)
|
||||
#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) PRES_ARENA_OBJECT(name_)
|
||||
#define DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#define DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifndef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#define PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(name_) /* nothing */
|
||||
#define DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifndef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#define PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(name_) /* nothing */
|
||||
#define DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#endif
|
||||
|
||||
// Use PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT to mention an nsPresArena-
|
||||
// allocated object that does not support ArenaRefPtr, and use
|
||||
// PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT to mention one that does.
|
||||
//
|
||||
// All PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT classes must be #included into
|
||||
// nsPresArena.cpp.
|
||||
//
|
||||
// Files including nsPresArenaObjectList.h can either define one or both
|
||||
// of PRES_ARENA_OBJECT_{WITH,WITHOUT}_ARENAREFPTR_SUPPORT to capture those
|
||||
// classes separately, or PRES_ARENA_OBJECT to capture all nsPresArena-
|
||||
// allocated classes.
|
||||
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsLineBox)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsRuleNode)
|
||||
PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT(nsStyleContext)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsInheritedStyleData)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsResetStyleData)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsConditionalResetStyleData)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsConditionalResetStyleDataEntry)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsFrameList)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(CustomCounterStyle)
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(DependentBuiltinCounterStyle)
|
||||
|
||||
#define STYLE_STRUCT(name_, checkdata_cb_) \
|
||||
PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT(nsStyle##name_)
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
||||
#ifdef DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#undef PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#undef DEFINED_PRES_ARENA_OBJECT_WITHOUT_ARENAREFPTR_SUPPORT
|
||||
#endif
|
||||
|
||||
#ifdef DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#undef PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#undef DEFINED_PRES_ARENA_OBJECT_WITH_ARENAREFPTR_SUPPORT
|
||||
#endif
|
||||
@@ -2789,6 +2789,15 @@ nsPresContext::IsDeviceSizePageSize()
|
||||
return isDeviceSizePageSize;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nsPresContext::GetRestyleGeneration() const
|
||||
{
|
||||
if (!mRestyleManager) {
|
||||
return 0;
|
||||
}
|
||||
return mRestyleManager->GetRestyleGeneration();
|
||||
}
|
||||
|
||||
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
|
||||
nsPresContextType aType)
|
||||
: nsPresContext(aDocument, aType),
|
||||
|
||||
@@ -914,6 +914,11 @@ public:
|
||||
mAllInvalidated = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RestyleManager's restyle generation counter.
|
||||
*/
|
||||
uint64_t GetRestyleGeneration() const;
|
||||
|
||||
/**
|
||||
* Returns whether there are any pending restyles or reflows.
|
||||
*/
|
||||
|
||||
@@ -1235,6 +1235,23 @@ PresShell::Destroy()
|
||||
mViewManager = nullptr;
|
||||
}
|
||||
|
||||
// mFrameArena will be destroyed soon. Clear out any ArenaRefPtrs
|
||||
// pointing to objects in the arena now. This is done:
|
||||
//
|
||||
// (a) before mFrameArena's destructor runs so that our
|
||||
// mPresArenaAllocCount gets down to 0 and doesn't trip the assertion
|
||||
// in ~PresShell,
|
||||
// (b) before the mPresContext->SetShell(nullptr) below, so
|
||||
// that when we clear the ArenaRefPtrs they'll still be able to
|
||||
// get back to this PresShell to deregister themselves (e.g. note
|
||||
// how nsStyleContext::Arena returns the PresShell got from its
|
||||
// rule node's nsPresContext, which would return null if we'd already
|
||||
// called mPresContext->SetShell(nullptr)), and
|
||||
// (c) before the mStyleSet->BeginShutdown() call just below, so that
|
||||
// the nsStyleContexts don't complain they're being destroyed later
|
||||
// than the rule tree is.
|
||||
mFrameArena.ClearArenaRefPtrs();
|
||||
|
||||
mStyleSet->BeginShutdown();
|
||||
nsRefreshDriver* rd = GetPresContext()->RefreshDriver();
|
||||
|
||||
@@ -2548,7 +2565,8 @@ PresShell::VerifyHasDirtyRootAncestor(nsIFrame* aFrame)
|
||||
|
||||
void
|
||||
PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
|
||||
nsFrameState aBitToAdd)
|
||||
nsFrameState aBitToAdd,
|
||||
ReflowRootHandling aRootHandling)
|
||||
{
|
||||
NS_PRECONDITION(aBitToAdd == NS_FRAME_IS_DIRTY ||
|
||||
aBitToAdd == NS_FRAME_HAS_DIRTY_CHILDREN ||
|
||||
@@ -2598,13 +2616,24 @@ PresShell::FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
|
||||
bool wasDirty = NS_SUBTREE_DIRTY(subtreeRoot);
|
||||
subtreeRoot->AddStateBits(aBitToAdd);
|
||||
|
||||
// Now if subtreeRoot is a reflow root we can cut off this reflow at it if
|
||||
// the bit being added is NS_FRAME_HAS_DIRTY_CHILDREN.
|
||||
bool targetFrameDirty = (aBitToAdd == NS_FRAME_IS_DIRTY);
|
||||
// Determine whether we need to keep looking for the next ancestor
|
||||
// reflow root if subtreeRoot itself is a reflow root.
|
||||
bool targetNeedsReflowFromParent;
|
||||
switch (aRootHandling) {
|
||||
case ePositionOrSizeChange:
|
||||
targetNeedsReflowFromParent = true;
|
||||
break;
|
||||
case eNoPositionOrSizeChange:
|
||||
targetNeedsReflowFromParent = false;
|
||||
break;
|
||||
case eInferFromBitToAdd:
|
||||
targetNeedsReflowFromParent = (aBitToAdd == NS_FRAME_IS_DIRTY);
|
||||
break;
|
||||
}
|
||||
|
||||
#define FRAME_IS_REFLOW_ROOT(_f) \
|
||||
((_f->GetStateBits() & NS_FRAME_REFLOW_ROOT) && \
|
||||
(_f != subtreeRoot || !targetFrameDirty))
|
||||
(_f != subtreeRoot || !targetNeedsReflowFromParent))
|
||||
|
||||
|
||||
// Mark the intrinsic widths as dirty on the frame, all of its ancestors,
|
||||
|
||||
@@ -112,7 +112,9 @@ public:
|
||||
|
||||
virtual nsIFrame* GetPlaceholderFrameFor(nsIFrame* aFrame) const override;
|
||||
virtual void FrameNeedsReflow(nsIFrame *aFrame, IntrinsicDirty aIntrinsicDirty,
|
||||
nsFrameState aBitToAdd) override;
|
||||
nsFrameState aBitToAdd,
|
||||
ReflowRootHandling aRootHandling =
|
||||
eInferFromBitToAdd) override;
|
||||
virtual void FrameNeedsToContinueReflow(nsIFrame *aFrame) override;
|
||||
virtual void CancelAllPendingReflows() override;
|
||||
virtual bool IsSafeToFlush() const override;
|
||||
|
||||
@@ -1135,6 +1135,29 @@ public:
|
||||
return mMargin.TopBottom();
|
||||
}
|
||||
|
||||
/*
|
||||
* Return margin values for line-relative sides, as defined in
|
||||
* http://www.w3.org/TR/css-writing-modes-3/#line-directions:
|
||||
*
|
||||
* line-left
|
||||
* Nominally the side from which LTR text would start.
|
||||
* line-right
|
||||
* Nominally the side from which RTL text would start. (Opposite of
|
||||
* line-left.)
|
||||
*/
|
||||
nscoord LineLeft(WritingMode aWritingMode) const
|
||||
{
|
||||
// We don't need to CHECK_WRITING_MODE here because the IStart or IEnd
|
||||
// accessor that we call will do it.
|
||||
return aWritingMode.IsBidiLTR()
|
||||
? IStart(aWritingMode) : IEnd(aWritingMode);
|
||||
}
|
||||
nscoord LineRight(WritingMode aWritingMode) const
|
||||
{
|
||||
return aWritingMode.IsBidiLTR()
|
||||
? IEnd(aWritingMode) : IStart(aWritingMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a LogicalSize representing the total size of the inline-
|
||||
* and block-dimension margins.
|
||||
@@ -1891,41 +1914,4 @@ nsStylePosition::MaxBSizeDependsOnContainer(mozilla::WritingMode aWM) const
|
||||
: MaxHeightDependsOnContainer();
|
||||
}
|
||||
|
||||
inline uint8_t
|
||||
nsStyleTableBorder::LogicalCaptionSide(mozilla::WritingMode aWM) const
|
||||
{
|
||||
// sanity-check that constants we're using have the expected relationships
|
||||
static_assert(NS_STYLE_CAPTION_SIDE_BSTART == mozilla::eLogicalSideBStart &&
|
||||
NS_STYLE_CAPTION_SIDE_BEND == mozilla::eLogicalSideBEnd &&
|
||||
NS_STYLE_CAPTION_SIDE_ISTART == mozilla::eLogicalSideIStart &&
|
||||
NS_STYLE_CAPTION_SIDE_IEND == mozilla::eLogicalSideIEnd,
|
||||
"bad logical caption-side values");
|
||||
static_assert((NS_STYLE_CAPTION_SIDE_TOP - NS_SIDE_TOP ==
|
||||
NS_STYLE_CAPTION_SIDE_BOTTOM - NS_SIDE_BOTTOM) &&
|
||||
(NS_STYLE_CAPTION_SIDE_LEFT - NS_SIDE_LEFT ==
|
||||
NS_STYLE_CAPTION_SIDE_RIGHT - NS_SIDE_RIGHT) &&
|
||||
(NS_STYLE_CAPTION_SIDE_LEFT - NS_SIDE_LEFT ==
|
||||
NS_STYLE_CAPTION_SIDE_TOP - NS_SIDE_TOP),
|
||||
"mismatch between caption-side and side values");
|
||||
switch (mCaptionSide) {
|
||||
case NS_STYLE_CAPTION_SIDE_TOP:
|
||||
case NS_STYLE_CAPTION_SIDE_RIGHT:
|
||||
case NS_STYLE_CAPTION_SIDE_BOTTOM:
|
||||
case NS_STYLE_CAPTION_SIDE_LEFT: {
|
||||
uint8_t side = mCaptionSide - (NS_STYLE_CAPTION_SIDE_TOP - NS_SIDE_TOP);
|
||||
return aWM.LogicalSideForPhysicalSide(mozilla::css::Side(side));
|
||||
}
|
||||
|
||||
case NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE:
|
||||
return aWM.IsVertical() ? aWM.LogicalSideForPhysicalSide(NS_SIDE_TOP)
|
||||
: NS_STYLE_CAPTION_SIDE_BSTART_OUTSIDE;
|
||||
|
||||
case NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE:
|
||||
return aWM.IsVertical() ? aWM.LogicalSideForPhysicalSide(NS_SIDE_BOTTOM)
|
||||
: NS_STYLE_CAPTION_SIDE_BEND_OUTSIDE;
|
||||
}
|
||||
MOZ_ASSERT(mCaptionSide <= NS_STYLE_CAPTION_SIDE_BEND_OUTSIDE);
|
||||
return mCaptionSide;
|
||||
}
|
||||
|
||||
#endif // WritingModes_h_
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body style="display: inline-flex;"><div><div style="display: ruby-base;">f<br style="display: ruby-base-container;"></div></div></body>
|
||||
</html>
|
||||
@@ -589,6 +589,7 @@ load 1146103.html
|
||||
load 1146107.html
|
||||
load 1146114.html
|
||||
load 1156222.html
|
||||
load 1157011.html
|
||||
load 1222783.xhtml
|
||||
load details-display-none-summary-1.html
|
||||
load details-display-none-summary-2.html
|
||||
|
||||
@@ -96,9 +96,13 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||
aMetrics.SetBlockStartAscent(0);
|
||||
|
||||
// Only when the BR is operating in a line-layout situation will it
|
||||
// behave like a BR. BR is suppressed when it is inside ruby frames.
|
||||
// behave like a BR. Additionally, we suppress breaks from BR inside
|
||||
// of ruby frames. To determine if we're inside ruby, we have to rely
|
||||
// on the *parent's* ShouldSuppressLineBreak() method, instead of our
|
||||
// own, because we may have custom "display" value that makes our
|
||||
// ShouldSuppressLineBreak() return false.
|
||||
nsLineLayout* ll = aReflowState.mLineLayout;
|
||||
if (ll && !StyleContext()->ShouldSuppressLineBreak()) {
|
||||
if (ll && !GetParent()->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
// Note that the compatibility mode check excludes AlmostStandards
|
||||
// mode, since this is the inline box model. See bug 161691.
|
||||
if ( ll->LineIsEmpty() ||
|
||||
@@ -165,7 +169,7 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||
BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlineMinISizeData *aData)
|
||||
{
|
||||
if (!StyleContext()->ShouldSuppressLineBreak()) {
|
||||
if (!GetParent()->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
@@ -174,7 +178,7 @@ BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
BRFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlinePrefISizeData *aData)
|
||||
{
|
||||
if (!StyleContext()->ShouldSuppressLineBreak()) {
|
||||
if (!GetParent()->StyleContext()->ShouldSuppressLineBreak()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -922,13 +922,13 @@ nsContainerFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
|
||||
AutoMaybeDisableFontInflation an(this);
|
||||
|
||||
WritingMode tableWM = GetParent()->GetWritingMode();
|
||||
uint8_t captionSide = StyleTableBorder()->LogicalCaptionSide(tableWM);
|
||||
uint8_t captionSide = StyleTableBorder()->mCaptionSide;
|
||||
|
||||
if (aWM.IsOrthogonalTo(tableWM)) {
|
||||
if (captionSide == NS_STYLE_CAPTION_SIDE_BSTART ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BSTART_OUTSIDE ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BEND ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BEND_OUTSIDE) {
|
||||
if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE) {
|
||||
// For an orthogonal caption on a block-dir side of the table,
|
||||
// shrink-wrap to min-isize.
|
||||
result.ISize(aWM) = GetMinISize(aRenderingContext);
|
||||
@@ -944,11 +944,11 @@ nsContainerFrame::ComputeAutoSize(nsRenderingContext* aRenderingContext,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (captionSide == NS_STYLE_CAPTION_SIDE_ISTART ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_IEND) {
|
||||
if (captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_RIGHT) {
|
||||
result.ISize(aWM) = GetMinISize(aRenderingContext);
|
||||
} else if (captionSide == NS_STYLE_CAPTION_SIDE_BSTART ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BEND) {
|
||||
} else if (captionSide == NS_STYLE_CAPTION_SIDE_TOP ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_BOTTOM) {
|
||||
// The outer frame constrains our available isize to the isize of
|
||||
// the table. Grow if our min-isize is bigger than that, but not
|
||||
// larger than the containing block isize. (It would really be nice
|
||||
|
||||
@@ -697,6 +697,17 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
||||
}
|
||||
}
|
||||
|
||||
if (nsLayoutUtils::HasCurrentAnimations(static_cast<nsIFrame*>(this))) {
|
||||
// If no new frame for this element is created by the end of the
|
||||
// restyling process, stop animations for this frame
|
||||
RestyleManager::AnimationsWithDestroyedFrame* adf =
|
||||
presContext->RestyleManager()->GetAnimationsWithDestroyedFrame();
|
||||
// AnimationsWithDestroyedFrame only lives during the restyling process.
|
||||
if (adf) {
|
||||
adf->Put(mContent, mStyleContext);
|
||||
}
|
||||
}
|
||||
|
||||
shell->NotifyDestroyingFrame(this);
|
||||
|
||||
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsFrameList.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIPresShell.h"
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "nsBidiPresUtils.h"
|
||||
#include "nsContainerFrame.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsILineIterator.h"
|
||||
#include "nsBidiPresUtils.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mozilla {
|
||||
namespace layout {
|
||||
@@ -24,7 +27,7 @@ const AlignedFrameListBytes gEmptyFrameListBytes = { 0 };
|
||||
void*
|
||||
nsFrameList::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
|
||||
{
|
||||
return aPresShell->AllocateByObjectID(nsPresArena::nsFrameList_id, sz);
|
||||
return aPresShell->AllocateByObjectID(eArenaObjectID_nsFrameList, sz);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -33,7 +36,7 @@ nsFrameList::Delete(nsIPresShell* aPresShell)
|
||||
NS_PRECONDITION(this != &EmptyList(), "Shouldn't Delete() this list");
|
||||
NS_ASSERTION(IsEmpty(), "Shouldn't Delete() a non-empty list");
|
||||
|
||||
aPresShell->FreeByObjectID(nsPresArena::nsFrameList_id, this);
|
||||
aPresShell->FreeByObjectID(eArenaObjectID_nsFrameList, this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1985,9 +1985,9 @@ IsSideCaption(nsIFrame* aFrame, const nsStyleDisplay* aStyleDisplay,
|
||||
if (aStyleDisplay->mDisplay != NS_STYLE_DISPLAY_TABLE_CAPTION) {
|
||||
return false;
|
||||
}
|
||||
uint8_t captionSide = aFrame->StyleTableBorder()->LogicalCaptionSide(aWM);
|
||||
return captionSide == NS_STYLE_CAPTION_SIDE_ISTART ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_IEND;
|
||||
uint8_t captionSide = aFrame->StyleTableBorder()->mCaptionSide;
|
||||
return captionSide == NS_STYLE_CAPTION_SIDE_LEFT ||
|
||||
captionSide == NS_STYLE_CAPTION_SIDE_RIGHT;
|
||||
}
|
||||
|
||||
static nsFlexContainerFrame*
|
||||
|
||||
@@ -81,15 +81,20 @@ protected:
|
||||
virtual ~nsLeafFrame();
|
||||
|
||||
/**
|
||||
* Return the intrinsic width of the frame's content area. Note that this
|
||||
* Return the intrinsic isize of the frame's content area. Note that this
|
||||
* should not include borders or padding and should not depend on the applied
|
||||
* styles.
|
||||
* One exception to this is that the intrinsic (logical) size of an <iframe>
|
||||
* depends on the writing-mode property (because the default intrinsic size
|
||||
* is specified physically, for compat reasons). This should be OK because a
|
||||
* change to writing-mode will trigger frame reconstruction anyhow, so the
|
||||
* result will remain consistent for any given frame once constructed.
|
||||
*/
|
||||
virtual nscoord GetIntrinsicISize() = 0;
|
||||
|
||||
/**
|
||||
* Return the intrinsic height of the frame's content area. This should not
|
||||
* include border or padding. This will only matter if the specified height
|
||||
* Return the intrinsic bsize of the frame's content area. This should not
|
||||
* include border or padding. This will only matter if the specified bsize
|
||||
* is auto. Note that subclasses must either implement this or override
|
||||
* Reflow and ComputeAutoSize; the default Reflow and ComputeAutoSize impls
|
||||
* call this method.
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "nsLineBox.h"
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/WritingModes.h"
|
||||
@@ -148,14 +149,14 @@ nsLineBox::NoteFramesMovedFrom(nsLineBox* aFromLine)
|
||||
void*
|
||||
nsLineBox::operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW
|
||||
{
|
||||
return aPresShell->AllocateByObjectID(nsPresArena::nsLineBox_id, sz);
|
||||
return aPresShell->AllocateByObjectID(eArenaObjectID_nsLineBox, sz);
|
||||
}
|
||||
|
||||
void
|
||||
nsLineBox::Destroy(nsIPresShell* aPresShell)
|
||||
{
|
||||
this->nsLineBox::~nsLineBox();
|
||||
aPresShell->FreeByObjectID(nsPresArena::nsLineBox_id, this);
|
||||
aPresShell->FreeByObjectID(eArenaObjectID_nsLineBox, this);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -594,19 +594,23 @@ nscoord
|
||||
nsSubDocumentFrame::GetIntrinsicISize()
|
||||
{
|
||||
if (!IsInline()) {
|
||||
return 0; // HTML <frame> has no useful intrinsic width
|
||||
return 0; // HTML <frame> has no useful intrinsic isize
|
||||
}
|
||||
|
||||
if (mContent->IsXULElement()) {
|
||||
return 0; // XUL <iframe> and <browser> have no useful intrinsic width
|
||||
return 0; // XUL <iframe> and <browser> have no useful intrinsic isize
|
||||
}
|
||||
|
||||
NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
|
||||
"Intrinsic width should come from the embedded document.");
|
||||
"Intrinsic isize should come from the embedded document.");
|
||||
|
||||
// We must be an HTML <iframe>. Default to a width of 300, for IE
|
||||
// We must be an HTML <iframe>. Default to size of 300px x 150px, for IE
|
||||
// compat (and per CSS2.1 draft).
|
||||
return nsPresContext::CSSPixelsToAppUnits(300);
|
||||
// This depends on the applied styles, which the comments in nsLeafFrame.h
|
||||
// say it should not, but we know it cannot change during the lifetime of
|
||||
// the frame because changing writing-mode leads to frame reconstruction.
|
||||
WritingMode wm = GetWritingMode();
|
||||
return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 150 : 300);
|
||||
}
|
||||
|
||||
nscoord
|
||||
@@ -620,10 +624,11 @@ nsSubDocumentFrame::GetIntrinsicBSize()
|
||||
}
|
||||
|
||||
NS_ASSERTION(ObtainIntrinsicSizeFrame() == nullptr,
|
||||
"Intrinsic height should come from the embedded document.");
|
||||
"Intrinsic bsize should come from the embedded document.");
|
||||
|
||||
// Use 150px, for compatibility with IE, and per CSS2.1 draft.
|
||||
return nsPresContext::CSSPixelsToAppUnits(150);
|
||||
// Use size of 300px x 150px, for compatibility with IE, and per CSS2.1 draft.
|
||||
WritingMode wm = GetWritingMode();
|
||||
return nsPresContext::CSSPixelsToAppUnits(wm.IsVertical() ? 300 : 150);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_FRAME_DUMP
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIPresShell.h"
|
||||
@@ -73,12 +74,12 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aDocument);
|
||||
|
||||
nsCOMArray<nsISupports> sheets;
|
||||
nsCOMArray<nsIStyleSheet> sheets;
|
||||
|
||||
nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
|
||||
MOZ_ASSERT(document);
|
||||
|
||||
// Get the agent, then user sheets in the style set.
|
||||
// Get the agent, then user and finally xbl sheets in the style set.
|
||||
nsIPresShell* presShell = document->GetShell();
|
||||
if (presShell) {
|
||||
nsStyleSet* styleSet = presShell->StyleSet();
|
||||
@@ -90,6 +91,17 @@ inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
|
||||
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
||||
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
||||
}
|
||||
nsAutoTArray<CSSStyleSheet*, 32> xblSheetArray;
|
||||
styleSet->AppendAllXBLStyleSheets(xblSheetArray);
|
||||
|
||||
// The XBL stylesheet array will quite often be full of duplicates. Cope:
|
||||
nsTHashtable<nsPtrHashKey<CSSStyleSheet>> sheetSet;
|
||||
for (CSSStyleSheet* sheet : xblSheetArray) {
|
||||
if (!sheetSet.Contains(sheet)) {
|
||||
sheetSet.PutEntry(sheet);
|
||||
sheets.AppendElement(sheet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the document sheets.
|
||||
@@ -290,6 +302,33 @@ inDOMUtils::GetRuleColumn(nsIDOMCSSRule* aRule, uint32_t* _retval)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
inDOMUtils::GetRelativeRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRule);
|
||||
|
||||
Rule* rule = aRule->GetCSSRule();
|
||||
if (!rule) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
uint32_t lineNumber = rule->GetLineNumber();
|
||||
CSSStyleSheet* sheet = rule->GetStyleSheet();
|
||||
if (sheet) {
|
||||
nsINode* owningNode = sheet->GetOwnerNode();
|
||||
if (owningNode) {
|
||||
nsCOMPtr<nsIStyleSheetLinkingElement> link =
|
||||
do_QueryInterface(owningNode);
|
||||
if (link) {
|
||||
lineNumber -= link->GetLineNumber() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*_retval = lineNumber;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
inDOMUtils::GetCSSLexer(const nsAString& aText, JSContext* aCx,
|
||||
JS::MutableHandleValue aResult)
|
||||
@@ -561,6 +600,7 @@ static void GetColorsForProperty(const uint32_t aParserVariant,
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement());
|
||||
}
|
||||
InsertNoDuplicates(aArray, NS_LITERAL_STRING("currentColor"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -623,12 +663,17 @@ inDOMUtils::GetSubpropertiesForCSSProperty(const nsAString& aProperty,
|
||||
nsCSSProperty propertyID =
|
||||
nsCSSProps::LookupProperty(aProperty, nsCSSProps::eEnabledForAllContent);
|
||||
|
||||
if (propertyID == eCSSProperty_UNKNOWN ||
|
||||
propertyID == eCSSPropertyExtra_variable) {
|
||||
if (propertyID == eCSSProperty_UNKNOWN) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<nsString> array;
|
||||
if (propertyID == eCSSPropertyExtra_variable) {
|
||||
*aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
|
||||
(*aValues)[0] = ToNewUnicode(aProperty);
|
||||
*aLength = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!nsCSSProps::IsShorthand(propertyID)) {
|
||||
*aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
|
||||
(*aValues)[0] = ToNewUnicode(nsCSSProps::GetStringValue(propertyID));
|
||||
@@ -663,7 +708,11 @@ inDOMUtils::CssPropertyIsShorthand(const nsAString& aProperty, bool *_retval)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*_retval = nsCSSProps::IsShorthand(propertyID);
|
||||
if (propertyID == eCSSPropertyExtra_variable) {
|
||||
*_retval = false;
|
||||
} else {
|
||||
*_retval = nsCSSProps::IsShorthand(propertyID);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,33 @@ interface inIDOMUtils : nsISupports
|
||||
[optional] out unsigned long aLength,
|
||||
[array, size_is (aLength), retval] out nsISupports aSheets);
|
||||
nsISupportsArray getCSSStyleRules(in nsIDOMElement aElement, [optional] in DOMString aPseudo);
|
||||
|
||||
/**
|
||||
* Get the line number of a rule.
|
||||
*
|
||||
* @param nsIDOMCSSRule aRule The rule.
|
||||
* @return The rule's line number. Line numbers are 1-based.
|
||||
*/
|
||||
unsigned long getRuleLine(in nsIDOMCSSRule aRule);
|
||||
|
||||
/**
|
||||
* Get the column number of a rule.
|
||||
*
|
||||
* @param nsIDOMCSSRule aRule The rule.
|
||||
* @return The rule's column number. Column numbers are 1-based.
|
||||
*/
|
||||
unsigned long getRuleColumn(in nsIDOMCSSRule aRule);
|
||||
|
||||
/**
|
||||
* Like getRuleLine, but if the rule is in a <style> element,
|
||||
* returns a line number relative to the start of the element.
|
||||
*
|
||||
* @param nsIDOMCSSRule aRule the rule to examine
|
||||
* @return the line number of the rule, possibly relative to the
|
||||
* <style> element
|
||||
*/
|
||||
unsigned long getRelativeRuleLine(in nsIDOMCSSRule aRule);
|
||||
|
||||
[implicit_jscontext]
|
||||
jsval getCSSLexer(in DOMString aText);
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@ support-files =
|
||||
[test_bug856317.html]
|
||||
[test_bug877690.html]
|
||||
[test_bug1006595.html]
|
||||
[test_bug1046140.html]
|
||||
[test_color_to_rgba.html]
|
||||
[test_css_property_is_shorthand.html]
|
||||
[test_css_property_is_valid.html]
|
||||
[test_getRelativeRuleLine.html]
|
||||
[test_get_all_style_sheets.html]
|
||||
[test_is_valid_css_color.html]
|
||||
[test_isinheritableproperty.html]
|
||||
|
||||
@@ -32,6 +32,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1006595
|
||||
arraysEqual(displaySubProps, [ "color" ],
|
||||
"'color' subproperties");
|
||||
|
||||
var varProps = utils.getSubpropertiesForCSSProperty("--foo");
|
||||
arraysEqual(varProps, ["--foo"], "'--foo' subproperties");
|
||||
|
||||
ok(utils.cssPropertyIsShorthand("padding"), "'padding' is a shorthand")
|
||||
ok(!utils.cssPropertyIsShorthand("color"), "'color' is not a shorthand")
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1046140
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1046140</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
var utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(SpecialPowers.Ci.inIDOMUtils);
|
||||
|
||||
try {
|
||||
utils.getSubpropertiesForCSSProperty("--foo");
|
||||
ok(false, "expected an exception");
|
||||
} catch(e) {
|
||||
ok(true, "getSubpropertiesForCSSProperty throws when passed a CSS variable");
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1046140">Mozilla Bug 1046140</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -45,7 +45,7 @@ function do_test() {
|
||||
var values = utils.getCSSValuesForProperty(prop);
|
||||
var expected = [ "initial", "inherit", "unset", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
|
||||
"beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood",
|
||||
"cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson",
|
||||
"cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "currentColor",
|
||||
"cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey",
|
||||
"darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred",
|
||||
"darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey",
|
||||
@@ -71,7 +71,7 @@ function do_test() {
|
||||
var values = utils.getCSSValuesForProperty(prop);
|
||||
var expected = [ "initial", "inherit", "unset", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure",
|
||||
"beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue",
|
||||
"chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue",
|
||||
"chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "currentColor", "cyan", "darkblue",
|
||||
"darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta",
|
||||
"darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue",
|
||||
"darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray",
|
||||
@@ -101,7 +101,7 @@ function do_test() {
|
||||
var expected = [ "-moz-calc", "initial", "unset", "-moz-use-text-color", "aliceblue",
|
||||
"antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet",
|
||||
"brown", "burlywood", "cadetblue", "calc", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk",
|
||||
"crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
|
||||
"crimson", "currentColor", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
|
||||
"darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
|
||||
"darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "dashed", "deeppink",
|
||||
"deepskyblue", "dimgray", "dimgrey", "dodgerblue", "dotted", "double", "fill", "firebrick", "floralwhite",
|
||||
@@ -131,7 +131,7 @@ function do_test() {
|
||||
"dashed", "solid", "double", "groove", "ridge", "inset", "outset", "-moz-use-text-color",
|
||||
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black",
|
||||
"blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse",
|
||||
"chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
|
||||
"chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "currentColor", "cyan", "darkblue", "darkcyan",
|
||||
"darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen",
|
||||
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray",
|
||||
"darkslategrey", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey",
|
||||
@@ -211,7 +211,7 @@ function do_test() {
|
||||
var expected = [ "-moz-calc", "initial", "unset", "-moz-use-text-color", "aliceblue",
|
||||
"antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet",
|
||||
"brown", "burlywood", "cadetblue", "calc", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk",
|
||||
"crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
|
||||
"crimson", "currentColor", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki",
|
||||
"darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
|
||||
"darkslateblue", "darkslategray", "darkslategrey", "darkturquoise", "darkviolet", "dashed", "deeppink",
|
||||
"deepskyblue", "dimgray", "dimgrey", "dodgerblue", "dotted", "double", "fill", "firebrick", "floralwhite",
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test inDOMUtils::CssPropertyIsShorthand</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript;version=1.8">
|
||||
let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(SpecialPowers.Ci.inIDOMUtils);
|
||||
|
||||
let tests = [
|
||||
{
|
||||
property: "color",
|
||||
expected: false
|
||||
},
|
||||
{
|
||||
property: "background",
|
||||
expected: true
|
||||
},
|
||||
{
|
||||
property: "--anything",
|
||||
expected: false
|
||||
}
|
||||
];
|
||||
|
||||
for (let {property, expected} of tests) {
|
||||
let result = utils.cssPropertyIsShorthand(property);
|
||||
is(result, expected, "checking whether " + property + " is shorthand");
|
||||
}
|
||||
|
||||
let sawException = false;
|
||||
try {
|
||||
let result = utils.cssPropertyIsShorthand("nosuchproperty");
|
||||
} catch (e) {
|
||||
sawException = true;
|
||||
}
|
||||
ok(sawException, "checking whether nosuchproperty throws");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test inDOMUtils::CssPropertyIsShorthand</h1>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,67 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test inDOMUtils::getRelativeRuleLine</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<style>
|
||||
@supports (not (whatever: 72 zq)) {
|
||||
#test {
|
||||
background-color: #f0c;
|
||||
}
|
||||
}
|
||||
|
||||
#test {
|
||||
color: #f0c;
|
||||
}
|
||||
</style>
|
||||
<style>#test { color: red; }</style>
|
||||
<style>
|
||||
@invalidatkeyword {
|
||||
}
|
||||
|
||||
#test {
|
||||
color: blue;
|
||||
}
|
||||
</style>
|
||||
<script type="application/javascript;version=1.8">
|
||||
let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
|
||||
.getService(SpecialPowers.Ci.inIDOMUtils);
|
||||
|
||||
let tests = [
|
||||
{ sheetNo: 0, ruleNo: 0, lineNo: 1, columnNo: 1 },
|
||||
{ sheetNo: 1, ruleNo: 0, lineNo: 2, columnNo: 15 },
|
||||
{ sheetNo: 1, ruleNo: 1, lineNo: 8, columnNo: 5 },
|
||||
{ sheetNo: 2, ruleNo: 0, lineNo: 1, columnNo: 1 },
|
||||
{ sheetNo: 3, ruleNo: 0, lineNo: 5, columnNo: 6 },
|
||||
];
|
||||
|
||||
function doTest() {
|
||||
for (let test of tests) {
|
||||
let sheet = document.styleSheets[test.sheetNo];
|
||||
let rule = sheet.cssRules[test.ruleNo];
|
||||
let line = utils.getRelativeRuleLine(rule);
|
||||
let column = utils.getRuleColumn(rule);
|
||||
info("testing sheet " + test.sheetNo + ", rule " + test.ruleNo);
|
||||
is(line, test.lineNo, "line number is correct");
|
||||
is(column, test.columnNo, "column number is correct");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(doTest);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Test inDOMUtils::getRelativeRuleLine</h1>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
@@ -11,7 +11,8 @@
|
||||
|
||||
// Color names
|
||||
let colors = utils.getCSSValuesForProperty("color");
|
||||
let notColor = ["hsl", "hsla", "inherit", "initial", "rgb", "rgba", "unset"];
|
||||
let notColor = ["hsl", "hsla", "inherit", "initial", "rgb", "rgba",
|
||||
"unset", "transparent", "currentColor"];
|
||||
for (let color of colors) {
|
||||
if (notColor.indexOf(color) !== -1) {
|
||||
continue;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="reftest-wait"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
onload="setTimeAndSnapshot(101, false)">
|
||||
<script xlink:href="smil-util.js" type="text/javascript"/>
|
||||
<title>Testing that opacity changes are reflected in patterns</title>
|
||||
|
||||
<defs>
|
||||
<pattern id="p" width="100%" height="100%">
|
||||
<g>
|
||||
<rect width="100%" height="100%" fill="lime" stroke="lime" stroke-width="1" opacity="0">
|
||||
<animate attributeName="opacity" values="0;1" dur="1s" begin="99s" fill="freeze" />
|
||||
</rect>
|
||||
</g>
|
||||
</pattern>
|
||||
</defs>
|
||||
|
||||
<rect width="100%" height="100%" fill="red"/>
|
||||
<rect width="100%" height="100%" fill="url(#p)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 839 B |
@@ -79,6 +79,8 @@ fails == anim-fillcolor-1.svg anim-standard-ref.svg # bug 436296
|
||||
== anim-fillopacity-1css.svg anim-standard-ref.svg
|
||||
== anim-fillopacity-1xml.svg anim-standard-ref.svg
|
||||
|
||||
== anim-opacity-01.svg lime.svg
|
||||
|
||||
== anim-height-done-1a.svg anim-standard-ref.svg
|
||||
== anim-height-done-1b.svg anim-standard-ref.svg
|
||||
== anim-height-done-2.svg lime.svg
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS filters: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#fixedmoves {
|
||||
position: absolute;
|
||||
top: 150px;
|
||||
left: 150px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="fixedmoves"></div>
|
||||
</body>
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS filters: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filters/#FilterProperty">
|
||||
<link rel="help" href="http://www.w3.org/2015/02/10-fx-minutes.html#action02">
|
||||
<link rel="match" href="filter-containing-block-dynamic-1-ref.html">
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changefilter {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 150px;
|
||||
left: 150px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changefilter" style="filter: blur(4px)">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changefilter = document.getElementById("changefilter");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changefilter.style.filter = "";
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS filters: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.fxtf.org/filters/#FilterProperty">
|
||||
<link rel="help" href="http://www.w3.org/2015/02/10-fx-minutes.html#action02">
|
||||
<link rel="match" href="filter-containing-block-dynamic-1-ref.html">
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changefilter {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changefilter">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changefilter = document.getElementById("changefilter");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changefilter.style.filter = "blur(0px)";
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,2 @@
|
||||
fails == filter-containing-block-dynamic-1a.html filter-containing-block-dynamic-1-ref.html # bug 1187851
|
||||
fails == filter-containing-block-dynamic-1b.html filter-containing-block-dynamic-1-ref.html # bug 1187851
|
||||
@@ -19,6 +19,9 @@ include css21/reftest.list
|
||||
# Conditional Rules Level 3
|
||||
include conditional3/reftest.list
|
||||
|
||||
# Filter Effects Module
|
||||
include filters/reftest.list
|
||||
|
||||
# Flexible Box Layout Module
|
||||
include flexbox/reftest.list
|
||||
|
||||
@@ -53,7 +56,7 @@ include text3/reftest.list
|
||||
include text-decor-3/reftest.list
|
||||
|
||||
# Transforms
|
||||
# include transforms/reftest.list
|
||||
include transforms/reftest.list
|
||||
|
||||
# Transitions
|
||||
# include transitions/reftest.list
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS transforms: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#fixedmoves {
|
||||
position: absolute;
|
||||
top: 150px;
|
||||
left: 150px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="fixedmoves"></div>
|
||||
</body>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS transforms: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#perspective-property">
|
||||
<link rel="match" href="containing-block-dynamic-1-ref.html">
|
||||
<meta name="assert" content="It also establishes a containing block (somewhat similar to position: relative), just like the transform property does.">
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changeperspective {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 150px;
|
||||
left: 150px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changeperspective" style="perspective: 1000px">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changeperspective = document.getElementById("changeperspective");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changeperspective.style.perspective = "";
|
||||
</script>
|
||||
</body>
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS transforms: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#perspective-property">
|
||||
<link rel="match" href="containing-block-dynamic-1-ref.html">
|
||||
<meta name="assert" content="It also establishes a containing block (somewhat similar to position: relative), just like the transform property does.">
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changeperspective {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changeperspective">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changeperspective = document.getElementById("changeperspective");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changeperspective.style.perspective = "1000px";
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,4 @@
|
||||
== transform-containing-block-dynamic-1a.html containing-block-dynamic-1-ref.html
|
||||
== transform-containing-block-dynamic-1b.html containing-block-dynamic-1-ref.html
|
||||
== perspective-containing-block-dynamic-1a.html containing-block-dynamic-1-ref.html
|
||||
== perspective-containing-block-dynamic-1b.html containing-block-dynamic-1-ref.html
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS transforms: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#transform-rendering">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#transform-property">
|
||||
<link rel="match" href="containing-block-dynamic-1-ref.html">
|
||||
<meta name="assert" content="For elements whose layout is governed by the CSS box model, any value other than none for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.">
|
||||
<meta name="assert" content="The object acts as a containing block for fixed positioned descendants."
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changetransform {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 150px;
|
||||
left: 150px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changetransform" style="transform: translateX(4px)">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changetransform = document.getElementById("changetransform");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changetransform.style.transform = "";
|
||||
</script>
|
||||
</body>
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>CSS transforms: Creating containing block for fixed positioned elements</title>
|
||||
<link rel="author" title="L. David Baron" href="http://dbaron.org/">
|
||||
<link rel="author" title="Mozilla" href="http://www.mozilla.org/">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#transform-rendering">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-transforms-1/#transform-property">
|
||||
<link rel="match" href="containing-block-dynamic-1-ref.html">
|
||||
<meta name="assert" content="For elements whose layout is governed by the CSS box model, any value other than none for the transform results in the creation of both a stacking context and a containing block. The object acts as a containing block for fixed positioned descendants.">
|
||||
<meta name="assert" content="The object acts as a containing block for fixed positioned descendants."
|
||||
<meta name="flags" content="dom">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0 }
|
||||
#changetransform {
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 100px;
|
||||
}
|
||||
|
||||
#abscovered {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: red;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#fixedmoves {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
background: green;
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div id="changetransform">
|
||||
<div id="abscovered"></div>
|
||||
<div id="fixedmoves"></div>
|
||||
</div>
|
||||
<script>
|
||||
var changetransform = document.getElementById("changetransform");
|
||||
var fixedmoves = document.getElementById("fixedmoves");
|
||||
var causeFlush = fixedmoves.offsetTop;
|
||||
changetransform.style.transform = "translateX(0px)";
|
||||
</script>
|
||||
</body>
|
||||
@@ -0,0 +1,3 @@
|
||||
<!DOCTYPE html>
|
||||
<p>There should be no red:</p>
|
||||
<div style="background: green; width: 100px; height: 100px;"></div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<p>There should be no red:</p>
|
||||
<div style="background: red; width: 100px; height: 100px; position: absolute; z-index: -1;"></div>
|
||||
<div style="background: green; writing-mode: vertical-rl; width: 100px;">
|
||||
<span style="writing-mode: vertical-lr; height: 100px;">
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body>div { margin: 50px 20px; width: 400px; height: 500px; border: 5px solid blue; }
|
||||
.abc { display: inline-block; border: 2px solid red; inline-size: 30px;
|
||||
writing-mode: vertical-lr; position: absolute; left: 0; top: 0; }
|
||||
.test { background: #aaa; position: absolute; left: 0; top: 0; width: 2em; height: 100%; }
|
||||
.rel { position: relative; }
|
||||
iframe {
|
||||
position: absolute; left: 0; top: 34px;
|
||||
background: yellow; border: 5px solid green;
|
||||
width: 300px; height: 150px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="rel">
|
||||
<div class="test"><span class="abc">abc</span><iframe src="data:text/html,hello"></iframe></div>
|
||||
</div>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta charset="utf-8">
|
||||
<style>
|
||||
body>div { margin: 50px 20px; width: 400px; height: 500px; border: 5px solid blue; }
|
||||
.abc { display: inline-block; border: 2px solid red; inline-size: 30px;
|
||||
writing-mode: vertical-rl; position: absolute; right: 0; top: 0; }
|
||||
.test { background: #aaa; position: absolute; right: 0; top: 0; width: 2em; height: 100%; }
|
||||
.rel { position: relative; }
|
||||
iframe {
|
||||
position: absolute; right: 0; top: 34px;
|
||||
background: yellow; border: 5px solid green;
|
||||
width: 300px; height: 150px;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<div class="rel">
|
||||
<div class="test"><span class="abc">abc</span><iframe src="data:text/html,hello"></iframe></div>
|
||||
</div>
|
||||
@@ -150,6 +150,9 @@ test-pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLin
|
||||
== 1172774-percent-padding-4.html 1172774-percent-vertical-ref.html
|
||||
== 1174450-intrinsic-sizing.html 1174450-intrinsic-sizing-ref.html
|
||||
== 1175789-underline-overline-1.html 1175789-underline-overline-1-ref.html
|
||||
== 1188061-1-nsChangeHint_ClearAncestorIntrinsics.html 1188061-1-nsChangeHint_ClearAncestorIntrinsics-ref.html
|
||||
== 1188061-2-nsChangeHint_UpdateComputedBSize.html 1188061-2-nsChangeHint_UpdateComputedBSize-ref.html
|
||||
== 1196887-1-computed-display-inline-block.html 1196887-1-computed-display-inline-block-ref.html
|
||||
|
||||
# Suite of tests from Gérard Talbot in bug 1079151
|
||||
include abspos/reftest.list
|
||||
|
||||
@@ -74,10 +74,6 @@ fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-pro
|
||||
fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-006.xht multicol-count-002-ref.xht
|
||||
fuzzy-if(winWidget,48,600) fuzzy-if(cocoaWidget,19,97) HTTP(../..) == wm-row-progression-007.xht multicol-count-002-ref.xht
|
||||
|
||||
fuzzy-if(Android,255,38) == table-caption-block-start-1.html table-caption-block-start-1-ref.html
|
||||
fuzzy-if(Android,255,38) == table-caption-block-end-1.html table-caption-block-end-1-ref.html
|
||||
== table-caption-inline-start-1.html table-caption-inline-start-1-ref.html
|
||||
== table-caption-inline-end-1.html table-caption-inline-end-1-ref.html
|
||||
fuzzy-if(Android,255,38) == table-caption-top-1.html table-caption-top-1-ref.html
|
||||
fuzzy-if(Android,255,38) == table-caption-bottom-1.html table-caption-bottom-1-ref.html
|
||||
== table-caption-left-1.html table-caption-left-1-ref.html
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
body > div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.t {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
}
|
||||
.c {
|
||||
background: cyan;
|
||||
text-align: center;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="width: 200px">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="h">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="width: 200px">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
</div>
|
||||
@@ -1,61 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
margin-bottom: 10px;
|
||||
caption-side: block-end;
|
||||
}
|
||||
td {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
padding: 0;
|
||||
}
|
||||
caption {
|
||||
background: cyan;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table class="h ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="h rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
@@ -1,53 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
body > div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.t {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
}
|
||||
.c {
|
||||
background: cyan;
|
||||
text-align: center;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<div class="c" style="width: 200px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="h">
|
||||
<div class="c" style="width: 200px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
@@ -1,61 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
margin-bottom: 10px;
|
||||
caption-side: block-start;
|
||||
}
|
||||
td {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
padding: 0;
|
||||
}
|
||||
caption {
|
||||
background: cyan;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table class="h ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="h rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
@@ -44,11 +44,11 @@ body > div {
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
</div>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 0px sans-serif;
|
||||
}
|
||||
body > div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.t {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
display: inline-block;
|
||||
}
|
||||
.c {
|
||||
background: cyan;
|
||||
text-align: center;
|
||||
min-block-size: 20px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="h">
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
</div>
|
||||
@@ -1,61 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
margin-bottom: 10px;
|
||||
caption-side: inline-end;
|
||||
}
|
||||
td {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
padding: 0;
|
||||
}
|
||||
caption {
|
||||
background: cyan;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table class="h ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="h rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
@@ -1,57 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 0px sans-serif;
|
||||
}
|
||||
body > div {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.t {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
display: inline-block;
|
||||
}
|
||||
.c {
|
||||
background: cyan;
|
||||
text-align: center;
|
||||
min-block-size: 20px;
|
||||
display: inline-block;
|
||||
font-size: 12px;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="h">
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="h">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="c" style="inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="c" style="inline-size: -moz-min-content">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
@@ -1,61 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset=utf-8>
|
||||
<style>
|
||||
html {
|
||||
font: 12px sans-serif;
|
||||
}
|
||||
.h {
|
||||
writing-mode: horizontal-tb;
|
||||
}
|
||||
.vlr {
|
||||
writing-mode: vertical-lr;
|
||||
}
|
||||
.vrl {
|
||||
writing-mode: vertical-rl;
|
||||
}
|
||||
.ltr {
|
||||
direction: ltr;
|
||||
}
|
||||
.rtl {
|
||||
direction: rtl;
|
||||
}
|
||||
table {
|
||||
border-spacing: 0;
|
||||
margin-bottom: 10px;
|
||||
caption-side: inline-start;
|
||||
}
|
||||
td {
|
||||
width: 200px;
|
||||
height: 100px;
|
||||
background: silver;
|
||||
padding: 0;
|
||||
}
|
||||
caption {
|
||||
background: cyan;
|
||||
min-block-size: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<table class="h ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="h rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
@@ -45,11 +45,21 @@ body > div {
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,17 @@ caption {
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
@@ -45,11 +45,21 @@ body > div {
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="t"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +55,17 @@ caption {
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vlr rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl ltr">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
<table class="vrl rtl">
|
||||
<caption>table caption</caption>
|
||||
<tr><td></td></tr>
|
||||
</table>
|
||||
|
||||
@@ -44,11 +44,11 @@ body > div {
|
||||
</div>
|
||||
|
||||
<div class="vlr">
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: bottom">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
<div class="vrl">
|
||||
<div class="c" style="display: inline-block; inline-size: -moz-min-content; vertical-align: top">table caption</div>
|
||||
<div class="t" style="display: inline-block"></div>
|
||||
<div class="c" style="height: 100px">table caption</div>
|
||||
<div class="t"></div>
|
||||
</div>
|
||||
|
||||
@@ -198,7 +198,9 @@ CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* a
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
|
||||
CommonAnimationManager::HasAttributeDependentStyle(
|
||||
AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult)
|
||||
{
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
@@ -219,6 +221,7 @@ CommonAnimationManager::RulesMatching(ElementRuleProcessorData* aData)
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,6 +241,7 @@ CommonAnimationManager::RulesMatching(PseudoElementRuleProcessorData* aData)
|
||||
nsIStyleRule *rule = GetAnimationRule(aData->mElement, aData->mPseudoType);
|
||||
if (rule) {
|
||||
aData->mRuleWalker->Forward(rule);
|
||||
aData->mRuleWalker->CurrentNode()->SetIsAnimationRule();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,6 +449,15 @@ AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
|
||||
// Don't apply transitions or animations to things inside of
|
||||
// pseudo-elements.
|
||||
// FIXME (Bug 522599): Add tests for this.
|
||||
|
||||
// Prevent structs from being cached on the rule node since we're inside
|
||||
// a pseudo-element, as we could determine cacheability differently
|
||||
// when walking the rule tree for a style context that is not inside
|
||||
// a pseudo-element. Note that nsRuleNode::GetStyle##name_ and GetStyleData
|
||||
// will never look at cached structs when we're animating things inside
|
||||
// a pseduo-element, so that we don't incorrectly return a struct that
|
||||
// is only appropriate for non-pseudo-elements.
|
||||
aRuleData->mConditions.SetUncacheable();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,8 @@ public:
|
||||
virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) override;
|
||||
virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) override;
|
||||
virtual nsRestyleHint
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData) override;
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult) override;
|
||||
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override;
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) override;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) override;
|
||||
|
||||
@@ -1731,6 +1731,15 @@ CSSStyleSheet::List(FILE* out, int32_t aIndent) const
|
||||
void
|
||||
CSSStyleSheet::ClearRuleCascades()
|
||||
{
|
||||
// We might be in ClearRuleCascades because we had a modification
|
||||
// to the sheet that resulted in an nsCSSSelector being destroyed.
|
||||
// Tell the RestyleManager for each document we're used in
|
||||
// so that they can drop any nsCSSSelector pointers (used for
|
||||
// eRestyle_SomeDescendants) in their mPendingRestyles.
|
||||
for (nsStyleSet* styleSet : mStyleSets) {
|
||||
styleSet->ClearSelectors();
|
||||
}
|
||||
|
||||
bool removedSheetFromRuleProcessorCache = false;
|
||||
if (mRuleProcessors) {
|
||||
nsCSSRuleProcessor **iter = mRuleProcessors->Elements(),
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "CounterStyleManager.h"
|
||||
|
||||
#include "mozilla/ArenaObjectID.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
@@ -973,7 +974,7 @@ public:
|
||||
void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
|
||||
{
|
||||
return aPresContext->PresShell()->AllocateByObjectID(
|
||||
nsPresArena::DependentBuiltinCounterStyle_id, sz);
|
||||
eArenaObjectID_DependentBuiltinCounterStyle, sz);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -981,7 +982,7 @@ private:
|
||||
{
|
||||
nsIPresShell* shell = mManager->PresContext()->PresShell();
|
||||
this->~DependentBuiltinCounterStyle();
|
||||
shell->FreeByObjectID(nsPresArena::DependentBuiltinCounterStyle_id, this);
|
||||
shell->FreeByObjectID(eArenaObjectID_DependentBuiltinCounterStyle, this);
|
||||
}
|
||||
|
||||
CounterStyleManager* mManager;
|
||||
@@ -1091,7 +1092,7 @@ public:
|
||||
void* operator new(size_t sz, nsPresContext* aPresContext) CPP_THROW_NEW
|
||||
{
|
||||
return aPresContext->PresShell()->AllocateByObjectID(
|
||||
nsPresArena::CustomCounterStyle_id, sz);
|
||||
eArenaObjectID_CustomCounterStyle, sz);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -1099,7 +1100,7 @@ private:
|
||||
{
|
||||
nsIPresShell* shell = mManager->PresContext()->PresShell();
|
||||
this->~CustomCounterStyle();
|
||||
shell->FreeByObjectID(nsPresArena::CustomCounterStyle_id, this);
|
||||
shell->FreeByObjectID(eArenaObjectID_CustomCounterStyle, this);
|
||||
}
|
||||
|
||||
const nsTArray<nsString>& GetSymbols();
|
||||
|
||||
@@ -62,7 +62,9 @@ SVGAttrAnimationRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessor
|
||||
}
|
||||
|
||||
/* virtual */ nsRestyleHint
|
||||
SVGAttrAnimationRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
|
||||
SVGAttrAnimationRuleProcessor::HasAttributeDependentStyle(
|
||||
AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult)
|
||||
{
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,8 @@ public:
|
||||
virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) override;
|
||||
virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) override;
|
||||
virtual nsRestyleHint
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData) override;
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult) override;
|
||||
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override;
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE override;
|
||||
|
||||
@@ -559,7 +559,7 @@ nsCSSSelector::ToString(nsAString& aString, CSSStyleSheet* aSheet,
|
||||
const nsCSSSelector *s = stack.ElementAt(index);
|
||||
stack.RemoveElementAt(index);
|
||||
|
||||
s->AppendToStringWithoutCombinators(aString, aSheet);
|
||||
s->AppendToStringWithoutCombinators(aString, aSheet, false);
|
||||
|
||||
// Append the combinator, if needed.
|
||||
if (!stack.IsEmpty()) {
|
||||
@@ -583,24 +583,85 @@ nsCSSSelector::ToString(nsAString& aString, CSSStyleSheet* aSheet,
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSSelector::AppendToStringWithoutCombinators
|
||||
(nsAString& aString, CSSStyleSheet* aSheet) const
|
||||
nsCSSSelector::AppendToStringWithoutCombinators(
|
||||
nsAString& aString,
|
||||
CSSStyleSheet* aSheet,
|
||||
bool aUseStandardNamespacePrefixes) const
|
||||
{
|
||||
AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false);
|
||||
AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false,
|
||||
aUseStandardNamespacePrefixes);
|
||||
|
||||
for (const nsCSSSelector* negation = mNegations; negation;
|
||||
negation = negation->mNegations) {
|
||||
aString.AppendLiteral(":not(");
|
||||
negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet,
|
||||
true);
|
||||
negation->AppendToStringWithoutCombinatorsOrNegations(
|
||||
aString, aSheet, true, aUseStandardNamespacePrefixes);
|
||||
aString.Append(char16_t(')'));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCString
|
||||
nsCSSSelector::RestrictedSelectorToString() const
|
||||
{
|
||||
MOZ_ASSERT(IsRestrictedSelector());
|
||||
|
||||
nsString result;
|
||||
AppendToStringWithoutCombinators(result, nullptr, true);
|
||||
return NS_ConvertUTF16toUTF8(result);
|
||||
}
|
||||
|
||||
static bool
|
||||
AppendStandardNamespacePrefixToString(nsAString& aString, int32_t aNameSpace)
|
||||
{
|
||||
if (aNameSpace == kNameSpaceID_Unknown) {
|
||||
// Wildcard namespace; no prefix to write.
|
||||
return false;
|
||||
}
|
||||
switch (aNameSpace) {
|
||||
case kNameSpaceID_None:
|
||||
break;
|
||||
case kNameSpaceID_XML:
|
||||
aString.AppendLiteral("xml");
|
||||
break;
|
||||
case kNameSpaceID_XHTML:
|
||||
aString.AppendLiteral("html");
|
||||
break;
|
||||
case kNameSpaceID_XLink:
|
||||
aString.AppendLiteral("xlink");
|
||||
break;
|
||||
case kNameSpaceID_XSLT:
|
||||
aString.AppendLiteral("xsl");
|
||||
break;
|
||||
case kNameSpaceID_XBL:
|
||||
aString.AppendLiteral("xbl");
|
||||
break;
|
||||
case kNameSpaceID_MathML:
|
||||
aString.AppendLiteral("math");
|
||||
break;
|
||||
case kNameSpaceID_RDF:
|
||||
aString.AppendLiteral("rdf");
|
||||
break;
|
||||
case kNameSpaceID_XUL:
|
||||
aString.AppendLiteral("xul");
|
||||
break;
|
||||
case kNameSpaceID_SVG:
|
||||
aString.AppendLiteral("svg");
|
||||
break;
|
||||
default:
|
||||
aString.AppendLiteral("ns");
|
||||
aString.AppendInt(aNameSpace);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
|
||||
(nsAString& aString, CSSStyleSheet* aSheet,
|
||||
bool aIsNegated) const
|
||||
bool aIsNegated,
|
||||
bool aUseStandardNamespacePrefixes) const
|
||||
{
|
||||
nsAutoString temp;
|
||||
bool isPseudoElement = IsPseudoElement();
|
||||
@@ -616,7 +677,18 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
|
||||
// null, that means that the only namespaces we could have are the
|
||||
// wildcard namespace (which can be implicit in this case) and the "none"
|
||||
// namespace, which then needs to be explicitly specified.
|
||||
if (!sheetNS) {
|
||||
if (aUseStandardNamespacePrefixes) {
|
||||
#ifdef DEBUG
|
||||
// We have no sheet to look up prefix information from. This is
|
||||
// only for debugging, so use some "standard" prefixes that
|
||||
// are recognizable.
|
||||
wroteNamespace =
|
||||
AppendStandardNamespacePrefixToString(aString, mNameSpace);
|
||||
if (wroteNamespace) {
|
||||
aString.Append(char16_t('|'));
|
||||
}
|
||||
#endif
|
||||
} else if (!sheetNS) {
|
||||
NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
|
||||
mNameSpace == kNameSpaceID_None,
|
||||
"How did we get this namespace?");
|
||||
@@ -740,7 +812,12 @@ nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
|
||||
aString.Append(char16_t('*'));
|
||||
aString.Append(char16_t('|'));
|
||||
} else if (list->mNameSpace != kNameSpaceID_None) {
|
||||
if (aSheet) {
|
||||
if (aUseStandardNamespacePrefixes) {
|
||||
#ifdef DEBUG
|
||||
AppendStandardNamespacePrefixToString(aString, list->mNameSpace);
|
||||
aString.Append(char16_t('|'));
|
||||
#endif
|
||||
} else if (aSheet) {
|
||||
nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
|
||||
nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
|
||||
// Default namespaces don't apply to attribute selectors, so
|
||||
|
||||
@@ -159,22 +159,27 @@ public:
|
||||
void ToString(nsAString& aString, mozilla::CSSStyleSheet* aSheet,
|
||||
bool aAppend = false) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsRestrictedSelector() const {
|
||||
return PseudoType() == nsCSSPseudoElements::ePseudo_NotPseudoElement;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCString RestrictedSelectorToString() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass);
|
||||
nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const;
|
||||
|
||||
void AppendToStringWithoutCombinators(nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet) const;
|
||||
void AppendToStringWithoutCombinatorsOrNegations(nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet,
|
||||
bool aIsNegated)
|
||||
const;
|
||||
void AppendToStringWithoutCombinators(
|
||||
nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet,
|
||||
bool aUseStandardNamespacePrefixes) const;
|
||||
void AppendToStringWithoutCombinatorsOrNegations(
|
||||
nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet,
|
||||
bool aIsNegated,
|
||||
bool aUseStandardNamespacePrefixes) const;
|
||||
// Returns true if this selector can have a namespace specified (which
|
||||
// happens if and only if the default namespace would apply to this
|
||||
// selector).
|
||||
|
||||
@@ -546,6 +546,22 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
|
||||
return GetAnimationRule(aElement, aStyleContext->GetPseudoType());
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationManager::StopAnimationsForElement(
|
||||
mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
AnimationCollection* collection =
|
||||
GetAnimations(aElement, aPseudoType, false);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
|
||||
collection->Destroy();
|
||||
}
|
||||
|
||||
struct KeyframeData {
|
||||
float mKey;
|
||||
uint32_t mIndex; // store original order since sort algorithm is not stable
|
||||
|
||||
@@ -308,6 +308,12 @@ public:
|
||||
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
|
||||
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
|
||||
|
||||
// Stop animations on the element. This method takes the real element
|
||||
// rather than the element for the generated content for animations on
|
||||
// ::before and ::after.
|
||||
void StopAnimationsForElement(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
protected:
|
||||
virtual ~nsAnimationManager() {}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user