Compare commits

...
Author SHA1 Message Date
Moonchild a6f632714f Merge branch 'redwood' into release 2020-08-31 05:54:39 +00:00
Moonchild b28effe2ea Remove unsupported CE keyword from HTMLLinkElement.webidl 2020-08-30 12:04:46 +00:00
Moonchild afd6edd667 Clobber for NSS update 2020-08-30 11:59:23 +00:00
Moonchild 582a1ce72a [NSS] Version and build bump 2020-08-30 11:59:14 +00:00
J.C. Jones 71ac56ba40 [NSS] Prevent slotLock race in NSC_GetTokenInfo
Basically, NSC_GetTokenInfo doesn't lock slot->slotLock before accessing slot
after obtaining it, even though slotLock is defined as its lock.
2020-08-30 11:59:06 +00:00
Moonchild ae184d09e6 Issue #1587 followup - Improve resilience of AbortSignals. 2020-08-30 11:58:58 +00:00
Moonchild 868f0755ae [misc/mar] Don't use a signed type for a length parameter. 2020-08-30 11:58:49 +00:00
Kris Maglione 5ca8fbd41c [DOM] Only construct JS-implemented objects if inner window is current. 2020-08-30 11:58:40 +00:00
Moonchild 549c8b9283 [media] Only include source error details in debugging scenarios.
Unless a user is debugging media errors, this detail is unnecessary to report
and could include sensitive data which could be abused by third-party
requesters. This aligns it with the standard success/error paradigms in normal
browsing situations.
2020-08-30 11:58:32 +00:00
Moonchild 77e8ba7eaf Issue #618 - Implement async attribute for inline module scripts. (uplift)
This commit does several things:
- Moves the pref check from ScriptLoader to ns[I]Document so it can be called on
the document.
- Changes the atrribute freezing function to a better name that takes the
document as a parameter.
- Sets the proper async/defer attributes on HTML script elements based on
keywords and whether they are module scripts or not.
2020-08-30 09:51:18 +00:00
Moonchild e854d58633 Issue #618 - (async) Keep track of script modes in a single mode state.
This simplifies handling of combinations of async/defer by assigning one and
only one state to scripts.
If async then always async > if defer or module then defer > otherwise blocking.
2020-08-30 09:48:07 +00:00
Moonchild d58cb8e11b Issue #618 - (async, preload) Correctly pass info about async/defer to parser.
This makes sure we don't block body-referred sub-resources by head-referenced
defer and async scripts. This is important for all script loads, not just
modules, but is added here because it was run into while implementing modules.
2020-08-30 09:47:49 +00:00
Moonchild 429a7bdb93 Issue #618 - (async) Split out function to add async request. 2020-08-30 09:40:15 +00:00
Moonchild 3f14e9ec5f Issue #618 - Rename some script load request flags to be more descriptive. 2020-08-30 09:40:03 +00:00
Moonchild aefb293793 Issue #618 - Make document.currentScript null in modules.
Because the spec says so.
2020-08-30 09:39:55 +00:00
Jon Coppeard c583315558 Issue #618 - Fix processing of non-parser-generated module scripts. 2020-08-30 09:39:45 +00:00
Jon Coppeard 834ecdc59a Issue #618 - Handle errors for inline module scripts and ensure we update the
module map after fetch errors.
2020-08-30 09:39:23 +00:00
Moonchild 798c2ed4f8 Issue #618 - Split SRI verification out from OnStreamComplete. 2020-08-30 09:39:13 +00:00
Moonchild 767b637c83 Issue #618 - Split handling of load errors out from OnStreamComplete. 2020-08-30 09:39:03 +00:00
Moonchild 702ad218b0 Issue #618 - Integrity for descendant module scripts should be the empty string
Because the spec says so.
2020-08-30 09:38:54 +00:00
Jon Coppeard b9af9c0c51 Issue #618 - Don't mute errors for module scripts because they always use CORS 2020-08-30 09:38:44 +00:00
Moonchild 9d6e28d3d0 Issue #618: Pass down referrer and referrer policy when fetching modules.
Because the spec says so.
2020-08-30 09:38:29 +00:00
Moonchild c735355ae1 Issue #618: Ignore 'event' and 'for' attributes for module scripts.
Because the spec says so.
2020-08-30 09:38:17 +00:00
Moonchild 10a10fd375 Issue #618 - Simplify module resolve hook to be a function pointer
This is an ahead-of time port to try and address #1624.
This is based on BZ 1461751 and Jon Coppeard's work in it.
2020-08-30 09:37:12 +00:00
Moonchild 1012dbe9e5 [js] Add some utility functions to get the current JS runtime. 2020-08-30 09:37:03 +00:00
Gaming4JC 9982c1f5cb Issue #618 - Keep track of which modules in a graph have been fetched using a visited set
Ref: BZ 1365187
2020-08-30 09:36:51 +00:00
Gaming4JC fe912e94e4 Issue #618 - Simplify module map interface
Ref: BZ 1365187
2020-08-30 09:36:41 +00:00
Gaming4JC 770b1c9071 Issue #618 - Align error handling for module scripts with the spec - Debug follow up
MODULE_STATUS_ERRORED is no more. Replacing with newer API.

Ref: BZ 1420420
2020-08-30 09:35:19 +00:00
Gaming4JC daf56131a7 Issue #618 - Lazily initialise module binding maps - Debug follow up
The added debug assertion does not work due to missing API.
They were added in BZ 1337491, 1395366, and others, but were primarily used for multi-threading.
This uses our existing non-multithreaded syntax instead, resolving a `no member named` build error.
2020-08-30 09:35:07 +00:00
Jon Coppeard d8686de401 Issue #618 - Record module dependency before starting fetch so that error
handling works correctly

Ref BZ 1395896
2020-08-30 09:33:58 +00:00
Moonchild c8a38346c8 Issue #618 - Lazily initialise module binding maps
Make it so they are not allocated on a background thread in a different zone to
the final module.

Ref: BZ 1372258
2020-08-30 09:33:33 +00:00
Moonchild 70bafe4df5 Issue #618 - Use a single slot for the module's environment object.
According to the spec this isn't created until the module is instantiated, but
we create it when we compile the module.
We stored this previously in InitialEnvironmentSlot and copied it to
EnvironmentSlot when it was supposed to be created, but we can just store it in
the latter slot straight away and check the module's status and return null if
it shouldn't exist yet.

This reduces the number of slots needed on a moduleObject to 17.

Re: BZ 1420412 Part 1
We can't implement the second part to further reduce our number of slots,
because it relies on SetProxyReservedSlot which in turn relies on
rearchitecturing JS proxies to make reserved slots dynamic. That's a rabbit hole
we really don't want to fall into.
So, we'll end up being a bit slower because it can't be in-line allocated with
having more than 16 slots, but so be it. I sincerely doubt it will make any
practical difference.
2020-08-30 09:33:21 +00:00
Moonchild 498b1ab0c8 Issue #618 - Align error handling for module scripts with the spec (again)
This updates module implementation to match spec regarding handling of
instantiation errors, after it was changed yet again, this time to not remember
instantiation errors, but instead immediately rethrow applicable ones.

Ref: BZ 1420420
2020-08-30 09:33:06 +00:00
Moonchild 2f145b6eda Issue #618 - Fix error events fired when loading JS module dependencies fail
When module dependencies fail, don't spam with errors for each import; only fire
the error event once.

Ref: BZ 1421259
2020-08-30 09:32:52 +00:00
Matt A. Tobin 06a092d08e Follow up to eb28b1f32 - Correct inputmethod build file by putting Keyboard.jsm back in EXTRA_JS_MODULES
JSMs are NOT Components.
2020-08-30 09:31:24 +00:00
Moonchild d107016d37 [js] Reinstate precise floating point model for all js sources. 2020-08-30 09:31:10 +00:00
Moonchild 63371593c0 Issue #457 - Silence SQLite compiler warning
Our use of SQLite explicitly avoids using MSVC's _msize which the lib would
notrmally use. This was set up this way in BZ bug 719579 for legitimate reasons
(because _msize would end up using the system symbol, which would crash trying
to get the size information from jemalloc allocations). Since we build the
SQLite lib separately there is no easy way to avoid this warning as it's not
directly linked against mozglue.dll which has the jemalloc functions it wants
for _msize when not using the system allocator. It is implicitly assuming the
function is an extern returning an int (with the call specifically  casting to
int) which is correct (well, correct _enough_, anyway) so the warning can
safely be ignored for our specific use as it all lines up at link time.
2020-08-30 09:30:50 +00:00
Moonchild ce1dc7e6c6 [db] Update SQLite lib to 3.33.0 2020-08-30 09:30:28 +00:00
Moonchild a4780ebaeb Issue #1629 - Uplift implementation of <link disabled> behavior for stylesheets. 2020-08-30 09:29:45 +00:00
Gaming4JC c384fa6e25 Issue #1620 - Intrinsic Aspect Ratio: Debug Follow up.
Newly introduced aspect-ratio property did not have CSS_PROP_LIST_EXCLUDE_INTERNAL defines, resulting in the following assertion:
\!nsCSSProps::PropHasFlags(p, (1<<28)) (properties defined outside of #ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL sections must not have the CSS_PROPERTY_INTERNAL flag), at ...layout/style/nsCSSProps.cpp:289

This patch resolves the assertion by adding #ifndef around the aspect-ratio property.
2020-08-30 09:24:25 +00:00
Moonchild 5e8e0d05a6 [CSS] Alias -webkit-appearance for compatibility reasons
Since this is supported as an alias by Firefox and Edge for the same
reasons and we have websites using this to (attempt to) override the
system-provided styling with their own, leaving out the only supported
keyword we'd otherwise have (with -moz- prefix) but still stating
-webkit-.

TODO: unprefix this completely and make the vendor prefixes aliases.
2020-08-30 09:24:02 +00:00
Andy bf95a03189 Issue #1620 - Enable Intrinsic Ratio by Default
A simpler name feels so much cleaner.
2020-08-30 09:23:46 +00:00
Andy c75e412f17 Issue #1620 - Remove Development Comments 2020-08-30 09:23:37 +00:00
Andy 0bbe6ec105 Issue #1620 - Use Intrinsic Aspect Ratio for Images (uplift) 2020-08-30 09:23:18 +00:00
Moonchild 48d31ea5eb Pref and disable getRootNode()
This is apparently used for fallback selection and if available it is "assumed"
Shadow DOM is also available, while this is a utility function.

Webcompat is a nightmare sometimes.
2020-08-07 21:30:12 +00:00
Matt A. Tobin 3cf0843679 Issue #1628 - Remove redundant PREF_EM_UPDATE_BACKGROUND_URL 2020-08-07 21:30:03 +00:00
Gaming4JC ff21776616 Issue #1621 - Part 4: Check whether node can be splited.
At first, HTMLEditor::GetActiveEditingHost might return null in this situation, we should check whether nullptr is returned. At second, SplitNodeDeep returns error since curent is design mode and selection node has no parent. So we should check error.

Ref: Bug 1350772
2020-08-07 21:29:45 +00:00
Gaming4JC 2f022ab1fa Issue #1621 - Part 3: Use nsIAtom to change attirbute if possible.
We can replace old nsIEditor API with nsIAtom version.

Ref: Bug 1324996
2020-08-07 21:29:36 +00:00
Gaming4JC 14e7f881be Issue #1621 - Part 2: Implement nsIAtom version of SetAttribute/RemoveAttribute/CloneAttirubte.
Add nsIAtom version of the following.
 - CloneAttribute
 - RemoveAttribute
 - RemoveAttributeOrEquivalent
 - SetAttribute
 - SetAttributeOrEquivalent

Ref: Bug 1324996
2020-08-07 21:29:27 +00:00
Gaming4JC 4f03fb2798 Issue #1621 - Part 1: CSSEditUtils should use atom for CSS property if possible.
There is a lot of string compare when using CSS property name. We should use nsGkAtoms instead.

Ref: Bug 1323138
2020-08-07 21:29:16 +00:00
Matt A. Tobin 3dd316f739 Issue #1625 - Allow MailNews Oauth2 support to be configured in confvars.sh
Baby has his bottle, you ok now?
2020-08-07 21:28:54 +00:00
Moonchild 972ab6d437 [js] Try to catch bad pointers for GC and bail if not valid. 2020-08-07 21:28:14 +00:00
Andy 83ae5bd019 Issue #1619 - Nits Picked 2020-08-07 21:28:03 +00:00
Andy c237a54f23 Issue #1619 - Add Vertical Writing Testcase
Ensures aspect ratio numerator and denominator aren't swapped in vertical writing modes.
https://bugzilla.mozilla.org/show_bug.cgi?id=1548768
2020-08-07 21:27:54 +00:00
Andy 8f72a673ca Issue #1619 - Missing Dimension Computation
This existed in Firefox before this bug.
I don't know if it came from a previous bug or was removed post-fork.
2020-08-07 21:27:40 +00:00
Andy 3266e0976f Issue #1619 - Convert Intrinsic Ratio to Float
https://bugzilla.mozilla.org/show_bug.cgi?id=1547792

Aspect Ratio handling simplified by using floating point integers:
- Multiplication of value (or inverse value) to a known side for Scaling
- No unequal equal values such as "4/3" vs "8/6" vs "20/15"
- Truly "Empty" aspect ratios, even if one dimension is not 0
2020-08-07 21:27:29 +00:00
Matt A. Tobin 4433519ae8 Add license header to media/webrtc/trunk/build/mac/find_sdk_uxp.py 2020-08-07 21:27:17 +00:00
Matt A. Tobin d419fe2d52 Use an alt script to properly determine the OSX SDK version 2020-08-07 21:27:03 +00:00
Gaming4JC c77c6de9ce Bug 1318570 - Clean up GetTextNode into TextEditRules.
EditorBase parameter of GetTextNode is unnecessary because it uses static method only. Also, we should return nsINode to reduce QI.

Resolves #1617
2020-08-07 21:26:33 +00:00
141 changed files with 24621 additions and 17940 deletions

No files matched your search

-1
View File
@@ -23,4 +23,3 @@
# don't change CLOBBER for WebIDL changes any more.
Clobber for NSS update
+4
View File
@@ -65,9 +65,13 @@ if CONFIG['MOZ_DEBUG']:
# Force using malloc_usable_size when building with jemalloc because _msize
# causes assertions on Win64. See bug 719579.
# This causes a known warning due to the way mozjemalloc is linked and the
# malloc_usable_size function not being available at compile time on MSVC
# so we suppress that particular warning (C4013)
if CONFIG['OS_ARCH'] == 'WINNT' and CONFIG['MOZ_MEMORY']:
DEFINES['HAVE_MALLOC_USABLE_SIZE'] = True
DEFINES['SQLITE_WITHOUT_MSIZE'] = True
CFLAGS += ['-wd4013']
# Omit unused functions to save some library footprint.
DEFINES['SQLITE_OMIT_DEPRECATED'] = True
+20958 -15503
View File
File diff suppressed because it is too large. Load diff
+1205 -888
View File
File diff suppressed because it is too large. Load diff
+8 -1
View File
@@ -56,9 +56,16 @@ AbortSignal::Aborted() const
void
AbortSignal::Abort()
{
MOZ_ASSERT(!mAborted);
// Re-entrancy guard
if (mAborted) {
return;
}
mAborted = true;
// We might be deleted as a result of aborting a follower, so ensure we
// stay alive until all followers have been aborted.
RefPtr<AbortSignal> pinThis = this;
// Let's inform the followers.
for (uint32_t i = 0; i < mFollowers.Length(); ++i) {
mFollowers[i]->Aborted();
+1 -1
View File
@@ -14,7 +14,7 @@ EXPORTS.mozilla.dom += [
'AbortSignal.h',
]
UNIFIED_SOURCES += [
SOURCES += [
'AbortController.cpp',
'AbortSignal.cpp',
]
+3 -2
View File
@@ -789,13 +789,14 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement,
// If this is a fragment parser, we don't want to observe.
// We don't support CORS for processing instructions
bool isAlternate;
bool isExplicitlyEnabled;
rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
CORS_NONE, mDocument->GetReferrerPolicy(),
integrity, mRunsToCompletion ? nullptr : this,
&isAlternate);
&isAlternate, &isExplicitlyEnabled);
NS_ENSURE_SUCCESS(rv, rv);
if (!isAlternate && !mRunsToCompletion) {
if ((!isAlternate || isExplicitlyEnabled) && !mRunsToCompletion) {
++mPendingSheetCount;
mScriptLoader->AddParserBlockingScriptExecutionBlocker();
}
+13
View File
@@ -12745,3 +12745,16 @@ nsIDocument::GetSelection(ErrorResult& aRv)
return nsGlobalWindow::Cast(window)->GetSelection(aRv);
}
bool
nsIDocument::ModuleScriptsEnabled()
{
static bool sEnabledForContent = false;
static bool sCachedPref = false;
if (!sCachedPref) {
sCachedPref = true;
Preferences::AddBoolVarCache(&sEnabledForContent, "dom.moduleScripts.enabled", false);
}
return nsContentUtils::IsChromeDoc(this) || sEnabledForContent;
}
+2
View File
@@ -2872,6 +2872,8 @@ public:
virtual void ScheduleIntersectionObserverNotification() = 0;
virtual void NotifyIntersectionObservers() = 0;
bool ModuleScriptsEnabled();
protected:
bool GetUseCounter(mozilla::UseCounter aUseCounter)
{
+5 -3
View File
@@ -393,8 +393,9 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
nsAutoString title, type, media;
bool isScoped;
bool isAlternate;
bool isExplicitlyEnabled;
GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate);
GetStyleSheetInfo(title, type, media, &isScoped, &isAlternate, &isExplicitlyEnabled);
if (!type.LowerCaseEqualsLiteral("text/css")) {
return NS_OK;
@@ -425,7 +426,7 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
// Parse the style sheet.
rv = doc->CSSLoader()->
LoadInlineStyle(thisContent, text, mLineNumber, title, media,
scopeElement, aObserver, &doneLoading, &isAlternate);
scopeElement, aObserver, &doneLoading, &isAlternate, &isExplicitlyEnabled);
}
else {
nsAutoString integrity;
@@ -452,13 +453,14 @@ nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument* aOldDocument,
rv = doc->CSSLoader()->
LoadStyleLink(thisContent, clonedURI, title, media, isAlternate,
GetCORSMode(), referrerPolicy, integrity,
aObserver, &isAlternate);
aObserver, &isAlternate, &isExplicitlyEnabled);
if (NS_FAILED(rv)) {
// Don't propagate LoadStyleLink() errors further than this, since some
// consumers (e.g. nsXMLContentSink) will completely abort on innocuous
// things like a stylesheet load being blocked by the security system.
doneLoading = true;
isAlternate = false;
isExplicitlyEnabled = false;
rv = NS_OK;
}
}
+2 -1
View File
@@ -98,7 +98,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) = 0;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) = 0;
virtual mozilla::CORSMode GetCORSMode() const
{
+6 -1
View File
@@ -2487,6 +2487,12 @@ ConstructJSImplementation(const char* aContractId,
{
AutoNoJSAPI nojsapi;
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
if (!window->IsCurrentInnerWindow()) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
// Get the XPCOM component containing the JS implementation.
nsresult rv;
nsCOMPtr<nsISupports> implISupports = do_CreateInstance(aContractId, &rv);
@@ -2501,7 +2507,6 @@ ConstructJSImplementation(const char* aContractId,
// and our global is a window.
nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
do_QueryInterface(implISupports);
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
if (gpi) {
JS::Rooted<JS::Value> initReturn(RootingCx());
rv = gpi->Init(window, &initReturn);
+1 -1
View File
@@ -324,7 +324,7 @@ HTMLImageElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
nsGenericHTMLElement::MapImageAlignAttributeInto(aAttributes, aData);
nsGenericHTMLElement::MapImageBorderAttributeInto(aAttributes, aData);
nsGenericHTMLElement::MapImageMarginAttributeInto(aAttributes, aData);
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData);
nsGenericHTMLElement::MapImageSizeAttributesInto(aAttributes, aData, true);
nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
}
+5
View File
@@ -206,6 +206,11 @@ public:
return GetReferrerPolicyAsEnum();
}
bool IsAwaitingLoad() const
{
return !!mPendingImageLoadTask;
}
int32_t X();
int32_t Y();
// Uses XPCOM GetLowsrc.
+47 -12
View File
@@ -33,6 +33,8 @@
#define LINK_ELEMENT_FLAG_BIT(n_) \
NODE_FLAG_BIT(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET + (n_))
#define LINK_DISABLED Preferences::GetBool("dom.link.disabled_attribute.enabled", true)
// Link element specific bits
enum {
// Indicates that a DNS Prefetch has been requested from this Link element.
@@ -92,9 +94,14 @@ NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLElement)
NS_IMPL_ELEMENT_CLONE(HTMLLinkElement)
bool
HTMLLinkElement::Disabled()
HTMLLinkElement::Disabled() const
{
if (LINK_DISABLED) {
return GetBoolAttr(nsGkAtoms::disabled);
}
StyleSheet* ss = GetSheet();
return ss && ss->Disabled();
}
@@ -107,8 +114,12 @@ HTMLLinkElement::GetMozDisabled(bool* aDisabled)
}
void
HTMLLinkElement::SetDisabled(bool aDisabled)
{
HTMLLinkElement::SetDisabled(bool aDisabled, ErrorResult& aRv)
{
if (LINK_DISABLED) {
return SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aRv);
}
if (StyleSheet* ss = GetSheet()) {
ss->SetDisabled(aDisabled);
}
@@ -117,11 +128,11 @@ HTMLLinkElement::SetDisabled(bool aDisabled)
NS_IMETHODIMP
HTMLLinkElement::SetMozDisabled(bool aDisabled)
{
SetDisabled(aDisabled);
return NS_OK;
ErrorResult rv;
SetDisabled(aDisabled, rv);
return rv.StealNSResult();
}
NS_IMPL_STRING_ATTR(HTMLLinkElement, Charset, charset)
NS_IMPL_URI_ATTR(HTMLLinkElement, Href, href)
NS_IMPL_STRING_ATTR(HTMLLinkElement, Hreflang, hreflang)
@@ -369,7 +380,8 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type)) {
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled))) {
bool dropSheet = false;
if (aName == nsGkAtoms::rel) {
nsAutoString value;
@@ -396,17 +408,24 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
dropSheet ||
(aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type));
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled)));
}
} else {
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
// If the disabled attribute is removed from a link element, the
// stylesheet may be explicitly enabled.
if (aNameSpaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::disabled && LINK_DISABLED) {
mExplicitlyEnabled = true;
}
// Since removing href or rel makes us no longer link to a
// stylesheet, force updates for those too.
if (aName == nsGkAtoms::href ||
aName == nsGkAtoms::rel ||
aName == nsGkAtoms::title ||
aName == nsGkAtoms::media ||
aName == nsGkAtoms::type) {
aName == nsGkAtoms::type ||
(LINK_DISABLED && aName == nsGkAtoms::disabled)) {
UpdateStyleSheetInternal(nullptr, nullptr, true);
}
if (aName == nsGkAtoms::href ||
@@ -499,13 +518,15 @@ HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsScoped = false;
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString rel;
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
@@ -515,6 +536,20 @@ HTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
return;
}
if (LINK_DISABLED) {
// Is the link disabled?
if (Disabled()) {
return;
}
// Is it explicitly enabled?
if (mExplicitlyEnabled) {
*aIsExplicitlyEnabled = true;
}
}
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
title.CompressWhitespace();
+12 -4
View File
@@ -84,8 +84,8 @@ public:
virtual bool HasDeferredDNSPrefetchRequest() override;
// WebIDL
bool Disabled();
void SetDisabled(bool aDisabled);
bool Disabled() const;
void SetDisabled(bool aDisabled, ErrorResult& aRv);
// XPCOM GetHref is fine.
void SetHref(const nsAString& aHref, ErrorResult& aRv)
{
@@ -179,10 +179,18 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
protected:
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
RefPtr<nsDOMTokenList> mRelList;
// The "explicitly enabled" flag. This flag is set whenever the 'disabled'
// attribute is explicitly unset, and makes alternate stylesheets not be
// disabled by default anymore.
//
// See https://github.com/whatwg/html/issues/3840#issuecomment-481034206.
bool mExplicitlyEnabled = false;
private:
RefPtr<ImportLoader> mImportLoader;
};
+13 -1
View File
@@ -9,6 +9,7 @@
#include "mozilla/dom/HTMLSourceElement.h"
#include "mozilla/dom/ElementInlines.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Preferences.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/MathAlgorithms.h"
#include "mozilla/AsyncEventDispatcher.h"
@@ -1245,7 +1246,18 @@ void HTMLMediaElement::NoSupportedMediaSourceError(const nsACString& aErrorDetai
if (mDecoder) {
ShutdownDecoder();
}
mErrorSink->SetError(MEDIA_ERR_SRC_NOT_SUPPORTED, aErrorDetails);
// aErrorDetails can include sensitive details like MimeType or HTTP Status
// Code. We should not leak this and pass a Generic Error Message unless the
// user has explicitly enabled error reporting for debugging purposes.
bool reportDetails = Preferences::GetBool("media.sourceErrorDetails.enabled", false);
if (reportDetails) {
mErrorSink->SetError(MEDIA_ERR_SRC_NOT_SUPPORTED, aErrorDetails);
} else {
mErrorSink->SetError(MEDIA_ERR_SRC_NOT_SUPPORTED,
NS_LITERAL_CSTRING("Failed to open media"));
}
ChangeDelayLoadStatus(false);
UpdateAudioChannelPlayingState();
RejectPromises(TakePendingPlayPromises(), NS_ERROR_DOM_MEDIA_NOT_SUPPORTED_ERR);
+15 -8
View File
@@ -279,12 +279,20 @@ HTMLScriptElement::GetScriptCharset(nsAString& charset)
}
void
HTMLScriptElement::FreezeUriAsyncDefer()
HTMLScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc)
{
if (mFrozen) {
return;
}
MOZ_ASSERT(!mIsModule && !mAsync && !mDefer && !mExternal);
// Determine whether this is a classic script or a module script.
nsAutoString type;
GetScriptType(type);
mIsModule = aOwnerDoc->ModuleScriptsEnabled() &&
!type.IsEmpty() && type.LowerCaseEqualsASCII("module");
// variation of this code in nsSVGScriptElement - check if changes
// need to be transfered when modifying. Note that we don't use GetSrc here
// because it will return the base URL when the attr value is "".
@@ -299,14 +307,13 @@ HTMLScriptElement::FreezeUriAsyncDefer()
// At this point mUri will be null for invalid URLs.
mExternal = true;
bool defer, async;
GetAsync(&async);
GetDefer(&defer);
mDefer = !async && defer;
mAsync = async;
}
bool defer, async;
GetAsync(&async);
mAsync = (mExternal || mIsModule) && async;
GetDefer(&defer);
mDefer = mExternal && !async && defer;
mFrozen = true;
}
+1 -1
View File
@@ -41,7 +41,7 @@ public:
virtual bool GetScriptType(nsAString& type) override;
virtual void GetScriptText(nsAString& text) override;
virtual void GetScriptCharset(nsAString& charset) override;
virtual void FreezeUriAsyncDefer() override;
virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override;
virtual CORSMode GetCORSMode() const override;
// nsIContent
+4 -2
View File
@@ -66,7 +66,7 @@ HTMLStyleElement::GetMozDisabled(bool* aDisabled)
}
bool
HTMLStyleElement::Disabled()
HTMLStyleElement::Disabled() const
{
StyleSheet* ss = GetSheet();
return ss && ss->Disabled();
@@ -222,12 +222,14 @@ HTMLStyleElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
+3 -2
View File
@@ -58,7 +58,7 @@ public:
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
bool Disabled();
bool Disabled() const;
void SetDisabled(bool aDisabled);
void SetMedia(const nsAString& aMedia, ErrorResult& aError)
{
@@ -87,7 +87,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
/**
* Common method to call from the various mutation observer methods.
* aContent is a content node that's either the one that changed or its
+43 -15
View File
@@ -1449,29 +1449,57 @@ nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAtt
void
nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aData)
nsRuleData* aData,
bool aMapAspectRatio)
{
if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)))
return;
auto* aWidth = aAttributes->GetAttr(nsGkAtoms::width);
auto* aHeight = aAttributes->GetAttr(nsGkAtoms::height);
// width: value
nsCSSValue* width = aData->ValueForWidth();
if (width->GetUnit() == eCSSUnit_Null) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
if (value && value->Type() == nsAttrValue::eInteger)
width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
else if (value && value->Type() == nsAttrValue::ePercent)
width->SetPercentValue(value->GetPercentValue());
if (aWidth) {
nsCSSValue* cWidth = aData->ValueForWidth();
if (cWidth->GetUnit() == eCSSUnit_Null) {
if (aWidth->Type() == nsAttrValue::eInteger)
cWidth->SetFloatValue((float)aWidth->GetIntegerValue(), eCSSUnit_Pixel);
else if (aWidth->Type() == nsAttrValue::ePercent)
cWidth->SetPercentValue(aWidth->GetPercentValue());
}
}
// height: value
nsCSSValue* height = aData->ValueForHeight();
if (height->GetUnit() == eCSSUnit_Null) {
const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
if (value && value->Type() == nsAttrValue::eInteger)
height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
else if (value && value->Type() == nsAttrValue::ePercent)
height->SetPercentValue(value->GetPercentValue());
if (aHeight) {
nsCSSValue* cHeight = aData->ValueForHeight();
if (cHeight->GetUnit() == eCSSUnit_Null) {
if (aHeight->Type() == nsAttrValue::eInteger)
cHeight->SetFloatValue((float)aHeight->GetIntegerValue(), eCSSUnit_Pixel);
else if (aHeight->Type() == nsAttrValue::ePercent)
cHeight->SetPercentValue(aHeight->GetPercentValue());
}
}
if (Preferences::GetBool("layout.css.intrinsic-aspect-ratio.enabled") &&
aMapAspectRatio && aWidth && aHeight) {
Maybe<double> w;
if (aWidth->Type() == nsAttrValue::eInteger) {
w.emplace(aWidth->GetIntegerValue());
} else if (aWidth->Type() == nsAttrValue::eDoubleValue) {
w.emplace(aWidth->GetDoubleValue());
}
Maybe<double> h;
if (aHeight->Type() == nsAttrValue::eInteger) {
h.emplace(aHeight->GetIntegerValue());
} else if (aHeight->Type() == nsAttrValue::eDoubleValue) {
h.emplace(aHeight->GetDoubleValue());
}
if (w && h && *w != 0 && *h != 0) {
nsCSSValue* aspect_ratio = aData->ValueForAspectRatio();
aspect_ratio->SetFloatValue((float(*w) / float(*h)), eCSSUnit_Number);
}
}
}
+3 -1
View File
@@ -712,10 +712,12 @@ public:
*
* @param aAttributes the list of attributes to map
* @param aData the returned rule data [INOUT]
* @param aMapAspectRatio map width and height attributes on aspect-ratio
* @see GetAttributeMappingFunction
*/
static void MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
nsRuleData* aData);
nsRuleData* aData,
bool = false);
/**
* Helper to map the background attribute
* into a style struct.
+2 -1
View File
@@ -6,10 +6,11 @@
EXTRA_COMPONENTS += [
'InputMethod.manifest',
'Keyboard.jsm',
'MozKeyboard.js',
]
EXTRA_JS_MODULES += ['Keyboard.jsm']
JAR_MANIFESTS += ['jar.mn']
MOCHITEST_CHROME_MANIFESTS += ['mochitest/chrome.ini']
+36 -9
View File
@@ -17,26 +17,54 @@ NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest,
mBaseURL,
mLoader,
mParent,
mModuleScript,
mImports)
NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement,
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion,
CORSMode aCORSMode,
const SRIMetadata &aIntegrity,
nsIURI* aReferrer,
mozilla::net::ReferrerPolicy aReferrerPolicy,
ScriptLoader* aLoader)
: ScriptLoadRequest(ScriptKind::Module,
aURI,
aElement,
aVersion,
aCORSMode,
aIntegrity),
aIntegrity,
aReferrer,
aReferrerPolicy),
mIsTopLevel(true),
mLoader(aLoader)
{}
mLoader(aLoader),
mVisitedSet(new VisitedURLSet())
{
mVisitedSet->PutEntry(aURI);
}
ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
ModuleLoadRequest* aParent)
: ScriptLoadRequest(ScriptKind::Module,
aURI,
aParent->mElement,
aParent->mJSVersion,
aParent->mCORSMode,
SRIMetadata(),
aParent->mURI,
aParent->mReferrerPolicy),
mIsTopLevel(false),
mLoader(aParent->mLoader),
mVisitedSet(aParent->mVisitedSet)
{
MOZ_ASSERT(mVisitedSet->Contains(aURI));
mIsInline = false;
mScriptMode = aParent->mScriptMode;
}
void ModuleLoadRequest::Cancel()
{
@@ -83,7 +111,7 @@ ModuleLoadRequest::ModuleLoaded()
// been loaded.
mModuleScript = mLoader->GetFetchedModule(mURI);
if (!mModuleScript || mModuleScript->IsErrored()) {
if (!mModuleScript || mModuleScript->HasParseError()) {
ModuleErrored();
return;
}
@@ -95,7 +123,7 @@ void
ModuleLoadRequest::ModuleErrored()
{
mLoader->CheckModuleDependenciesLoaded(this);
MOZ_ASSERT(!mModuleScript || mModuleScript->IsErrored());
MOZ_ASSERT(!mModuleScript || mModuleScript->HasParseError());
CancelImports();
SetReady();
@@ -132,8 +160,7 @@ ModuleLoadRequest::LoadFinished()
{
mLoader->ProcessLoadedModuleTree(this);
mLoader = nullptr;
mParent = nullptr;
}
} // dom namespace
} // mozilla namespace
} // mozilla namespace
+26 -7
View File
@@ -8,6 +8,7 @@
#define mozilla_dom_ModuleLoadRequest_h
#include "mozilla/dom/ScriptLoader.h"
#include "nsURIHashKey.h"
#include "mozilla/MozPromise.h"
namespace mozilla {
@@ -16,6 +17,16 @@ namespace dom {
class ModuleScript;
class ScriptLoader;
// A reference counted set of URLs we have visited in the process of loading a
// module graph.
class VisitedURLSet : public nsTHashtable<nsURIHashKey>
{
NS_INLINE_DECL_REFCOUNTING(VisitedURLSet)
private:
~VisitedURLSet() = default;
};
// A load request for a module, created for every top level module script and
// every module import. Load request can share a ModuleScript if there are
// multiple imports of the same module.
@@ -31,12 +42,20 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
ModuleLoadRequest(nsIScriptElement* aElement,
// Create a top-level module load request.
ModuleLoadRequest(nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion,
CORSMode aCORSMode,
const SRIMetadata& aIntegrity,
nsIURI* aReferrer,
mozilla::net::ReferrerPolicy,
ScriptLoader* aLoader);
// Create a module load request for an imported module.
ModuleLoadRequest(nsIURI* aURI,
ModuleLoadRequest* aParent);
bool IsTopLevel() const {
return mIsTopLevel;
}
@@ -55,7 +74,7 @@ private:
public:
// Is this a request for a top level module script or an import?
bool mIsTopLevel;
const bool mIsTopLevel;
// The base URL used for resolving relative module imports.
nsCOMPtr<nsIURI> mBaseURL;
@@ -64,10 +83,6 @@ public:
// finishes.
RefPtr<ScriptLoader> mLoader;
// The importing module, or nullptr for top level module scripts. Used to
// implement the ancestor list checked when fetching module dependencies.
RefPtr<ModuleLoadRequest> mParent;
// Set to a module script object after a successful load or nullptr on
// failure.
RefPtr<ModuleScript> mModuleScript;
@@ -79,9 +94,13 @@ public:
// Array of imported modules.
nsTArray<RefPtr<ModuleLoadRequest>> mImports;
// Set of module URLs visited while fetching the module graph this request is
// part of.
RefPtr<VisitedURLSet> mVisitedSet;
};
} // dom namespace
} // mozilla namespace
#endif // mozilla_dom_ModuleLoadRequest_h
#endif // mozilla_dom_ModuleLoadRequest_h
+17 -26
View File
@@ -26,7 +26,8 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
tmp->UnlinkModuleRecord();
tmp->mError.setUndefined();
tmp->mParseError.setUndefined();
tmp->mErrorToRethrow.setUndefined();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
@@ -35,7 +36,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mError)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
@@ -48,7 +50,8 @@ ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL)
MOZ_ASSERT(mLoader);
MOZ_ASSERT(mBaseURL);
MOZ_ASSERT(!mModuleRecord);
MOZ_ASSERT(mError.isUndefined());
MOZ_ASSERT(!HasParseError());
MOZ_ASSERT(!HasErrorToRethrow());
}
void
@@ -74,7 +77,8 @@ void
ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
{
MOZ_ASSERT(!mModuleRecord);
MOZ_ASSERT(mError.isUndefined());
MOZ_ASSERT(!HasParseError());
MOZ_ASSERT(!HasErrorToRethrow());
mModuleRecord = aModuleRecord;
@@ -85,37 +89,24 @@ ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord)
}
void
ModuleScript::SetPreInstantiationError(const JS::Value& aError)
ModuleScript::SetParseError(const JS::Value& aError)
{
MOZ_ASSERT(!aError.isUndefined());
MOZ_ASSERT(!HasParseError());
MOZ_ASSERT(!HasErrorToRethrow());
UnlinkModuleRecord();
mError = aError;
mParseError = aError;
HoldJSObjects(this);
}
bool
ModuleScript::IsErrored() const
void
ModuleScript::SetErrorToRethrow(const JS::Value& aError)
{
if (!mModuleRecord) {
MOZ_ASSERT(!mError.isUndefined());
return true;
}
MOZ_ASSERT(!aError.isUndefined());
MOZ_ASSERT(!HasErrorToRethrow());
return JS::IsModuleErrored(mModuleRecord);
}
JS::Value
ModuleScript::Error() const
{
MOZ_ASSERT(IsErrored());
if (!mModuleRecord) {
return mError;
}
return JS::GetModuleError(mModuleRecord);
mErrorToRethrow = aError;
}
} // dom namespace
+8 -4
View File
@@ -23,7 +23,8 @@ class ModuleScript final : public nsISupports
RefPtr<ScriptLoader> mLoader;
nsCOMPtr<nsIURI> mBaseURL;
JS::Heap<JSObject*> mModuleRecord;
JS::Heap<JS::Value> mError;
JS::Heap<JS::Value> mParseError;
JS::Heap<JS::Value> mErrorToRethrow;
~ModuleScript();
@@ -35,14 +36,17 @@ public:
nsIURI* aBaseURL);
void SetModuleRecord(JS::Handle<JSObject*> aModuleRecord);
void SetPreInstantiationError(const JS::Value& aError);
void SetParseError(const JS::Value& aError);
void SetErrorToRethrow(const JS::Value& aError);
ScriptLoader* Loader() const { return mLoader; }
JSObject* ModuleRecord() const { return mModuleRecord; }
nsIURI* BaseURL() const { return mBaseURL; }
bool IsErrored() const;
JS::Value Error() const;
JS::Value ParseError() const { return mParseError; }
JS::Value ErrorToRethrow() const { return mErrorToRethrow; }
bool HasParseError() const { return !mParseError.isUndefined(); }
bool HasErrorToRethrow() const { return !mErrorToRethrow.isUndefined(); }
void UnlinkModuleRecord();
};
+4 -4
View File
@@ -21,11 +21,11 @@ using namespace mozilla::dom;
NS_IMETHODIMP
ScriptElement::ScriptAvailable(nsresult aResult,
nsIScriptElement *aElement,
bool aIsInline,
bool aIsInlineClassicScript,
nsIURI *aURI,
int32_t aLineNo)
{
if (!aIsInline && NS_FAILED(aResult)) {
if (!aIsInlineClassicScript && NS_FAILED(aResult)) {
nsCOMPtr<nsIParser> parser = do_QueryReferent(mCreatorParser);
if (parser) {
parser->PushDefinedInsertionPoint();
@@ -128,11 +128,11 @@ ScriptElement::MaybeProcessScript()
return false;
}
FreezeUriAsyncDefer();
nsIDocument* ownerDoc = cont->OwnerDoc();
FreezeExecutionAttrs(ownerDoc);
mAlreadyStarted = true;
nsIDocument* ownerDoc = cont->OwnerDoc();
nsCOMPtr<nsIParser> parser = ((nsIScriptElement*) this)->GetCreatorParser();
if (parser) {
nsCOMPtr<nsIContentSink> sink = parser->GetContentSink();
File diff suppressed because it is too large. Load diff
+66 -23
View File
@@ -62,17 +62,21 @@ protected:
public:
ScriptLoadRequest(ScriptKind aKind,
nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion,
mozilla::CORSMode aCORSMode,
const mozilla::dom::SRIMetadata &aIntegrity)
const SRIMetadata& aIntegrity,
nsIURI* aReferrer,
mozilla::net::ReferrerPolicy aReferrerPolicy)
: mKind(aKind),
mElement(aElement),
mProgress(Progress::Loading),
mScriptMode(ScriptMode::eBlocking),
mIsInline(true),
mHasSourceMapURL(false),
mIsDefer(false),
mIsAsync(false),
mInDeferList(false),
mInAsyncList(false),
mIsNonAsyncScriptInserted(false),
mIsXSLT(false),
mIsCanceled(false),
@@ -81,10 +85,12 @@ public:
mScriptTextBuf(nullptr),
mScriptTextLength(0),
mJSVersion(aVersion),
mURI(aURI),
mLineNo(1),
mCORSMode(aCORSMode),
mIntegrity(aIntegrity),
mReferrerPolicy(mozilla::net::RP_Default)
mReferrer(aReferrer),
mReferrerPolicy(aReferrerPolicy)
{
}
@@ -100,7 +106,8 @@ public:
void FireScriptAvailable(nsresult aResult)
{
mElement->ScriptAvailable(aResult, mElement, mIsInline, mURI, mLineNo);
bool isInlineClassicScript = mIsInline && !IsModuleRequest();
mElement->ScriptAvailable(aResult, mElement, isInlineClassicScript, mURI, mLineNo);
}
void FireScriptEvaluated(nsresult aResult)
{
@@ -143,6 +150,29 @@ public:
(IsReadyToRun() && mWasCompiledOMT);
}
enum class ScriptMode : uint8_t {
eBlocking,
eDeferred,
eAsync
};
void SetScriptMode(bool aDeferAttr, bool aAsyncAttr);
bool IsBlockingScript() const
{
return mScriptMode == ScriptMode::eBlocking;
}
bool IsDeferredScript() const
{
return mScriptMode == ScriptMode::eDeferred;
}
bool IsAsyncScript() const
{
return mScriptMode == ScriptMode::eAsync;
}
void MaybeCancelOffThreadScript();
using super::getNext;
@@ -151,10 +181,11 @@ public:
const ScriptKind mKind;
nsCOMPtr<nsIScriptElement> mElement;
Progress mProgress; // Are we still waiting for a load to complete?
ScriptMode mScriptMode; // Whether this script is blocking, deferred or async.
bool mIsInline; // Is the script inline or loaded?
bool mHasSourceMapURL; // Does the HTTP header have a source map url?
bool mIsDefer; // True if we live in mDeferRequests.
bool mIsAsync; // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
bool mInDeferList; // True if we live in mDeferRequests.
bool mInAsyncList; // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
bool mIsXSLT; // True if we live in mXSLTRequests.
bool mIsCanceled; // True if we have been explicitly canceled.
@@ -164,13 +195,14 @@ public:
char16_t* mScriptTextBuf; // Holds script text for non-inline scripts. Don't
size_t mScriptTextLength; // use nsString so we can give ownership to jsapi.
uint32_t mJSVersion;
nsCOMPtr<nsIURI> mURI;
const nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIPrincipal> mOriginPrincipal;
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
int32_t mLineNo;
const mozilla::CORSMode mCORSMode;
const mozilla::dom::SRIMetadata mIntegrity;
mozilla::net::ReferrerPolicy mReferrerPolicy;
const SRIMetadata mIntegrity;
const nsCOMPtr<nsIURI> mReferrer;
const mozilla::net::ReferrerPolicy mReferrerPolicy;
};
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest>
@@ -452,6 +484,8 @@ public:
const nsAString &aCrossOrigin,
const nsAString& aIntegrity,
bool aScriptFromHead,
bool aAsync,
bool aDefer,
const mozilla::net::ReferrerPolicy aReferrerPolicy);
/**
@@ -467,12 +501,13 @@ public:
private:
virtual ~ScriptLoader();
ScriptLoadRequest* CreateLoadRequest(
ScriptKind aKind,
nsIScriptElement* aElement,
uint32_t aVersion,
mozilla::CORSMode aCORSMode,
const mozilla::dom::SRIMetadata &aIntegrity);
ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind,
nsIURI* aURI,
nsIScriptElement* aElement,
uint32_t aVersion,
mozilla::CORSMode aCORSMode,
const SRIMetadata& aIntegrity,
mozilla::net::ReferrerPolicy aReferrerPolicy);
/**
* Unblocks the creator parser of the parser-blocking scripts.
@@ -500,6 +535,8 @@ private:
nsresult StartLoad(ScriptLoadRequest *aRequest, const nsAString &aType,
bool aScriptFromHead);
void HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult);
/**
* Process any pending requests asynchronously (i.e. off an event) if there
* are any. Note that this is a no-op if there aren't any currently pending
@@ -534,6 +571,11 @@ private:
return mEnabled && !mBlockerCount;
}
nsresult VerifySRI(ScriptLoadRequest *aRequest,
nsIIncrementalStreamLoader* aLoader,
nsresult aSRIStatus,
SRICheckDataVerifier* aSRIDataVerifier) const;
nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest);
nsresult ProcessRequest(ScriptLoadRequest* aRequest);
nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
@@ -556,6 +598,7 @@ private:
mozilla::Vector<char16_t> &aString);
void AddDeferRequest(ScriptLoadRequest* aRequest);
void AddAsyncRequest(ScriptLoadRequest* aRequest);
bool MaybeRemovedDeferRequests();
void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
@@ -563,30 +606,30 @@ private:
JS::SourceBufferHolder GetScriptSource(ScriptLoadRequest* aRequest,
nsAutoString& inlineData);
bool ModuleScriptsEnabled();
void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest *aRequest,
nsresult aResult);
bool IsFetchingModule(ModuleLoadRequest *aRequest) const;
bool ModuleMapContainsModule(ModuleLoadRequest *aRequest) const;
RefPtr<mozilla::GenericPromise> WaitForModuleFetch(ModuleLoadRequest *aRequest);
bool ModuleMapContainsURL(nsIURI* aURL) const;
RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
ModuleScript* GetFetchedModule(nsIURI* aURL) const;
friend bool
HostResolveImportedModule(JSContext* aCx, unsigned argc, JS::Value* vp);
friend JSObject*
HostResolveImportedModule(JSContext* aCx, JS::Handle<JSObject*> aModule,
JS::Handle<JSString*> aSpecifier);
nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
JS::Value FindFirstParseError(ModuleLoadRequest* aRequest);
bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
RefPtr<mozilla::GenericPromise>
StartFetchingModuleAndDependencies(ModuleLoadRequest* aRequest, nsIURI* aURI);
StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI);
nsIDocument* mDocument; // [WEAK]
nsCOMArray<nsIScriptLoaderObserver> mObservers;
+25 -4
View File
@@ -13,6 +13,7 @@
#include "nsIScriptLoaderObserver.h"
#include "nsWeakPtr.h"
#include "nsIParser.h"
#include "nsIDocument.h"
#include "nsContentCreatorFunctions.h"
#include "nsIDOMHTMLScriptElement.h"
#include "mozilla/CORSMode.h"
@@ -37,6 +38,7 @@ public:
mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
mFrozen(false),
mIsModule(false),
mDefer(false),
mAsync(false),
mExternal(false),
@@ -73,11 +75,25 @@ public:
virtual void GetScriptCharset(nsAString& charset) = 0;
/**
* Freezes the return values of GetScriptDeferred(), GetScriptAsync() and
* GetScriptURI() so that subsequent modifications to the attributes don't
* change execution behavior.
* Freezes the return values of the following methods so that subsequent
* modifications to the attributes don't change execution behavior:
* - GetScriptIsModule()
* - GetScriptDeferred()
* - GetScriptAsync()
* - GetScriptURI()
* - GetScriptExternal()
*/
virtual void FreezeUriAsyncDefer() = 0;
virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) = 0;
/**
* Is the script a module script?
* Currently only supported by HTML scripts.
*/
bool GetScriptIsModule()
{
NS_PRECONDITION(mFrozen, "Execution attributes not yet frozen: Not ready for this call!");
return mIsModule;
}
/**
* Is the script deferred. Currently only supported by HTML scripts.
@@ -292,6 +308,11 @@ protected:
*/
bool mFrozen;
/**
* The effective moduleness.
*/
bool mIsModule;
/**
* The effective deferredness.
*/
+5 -4
View File
@@ -20,15 +20,16 @@ interface nsIScriptLoaderObserver : nsISupports {
* a script. If this is a failure code, script evaluation
* will not occur.
* @param aElement The element being processed.
* @param aIsInline Is this an inline script or externally loaded?
* @param aIsInline Is this an inline classic script (as opposed to an
* externally loaded classic script or module script)?
* @param aURI What is the URI of the script (the document URI if
* it is inline).
* @param aLineNo At what line does the script appear (generally 1
* if it is a loaded script).
*/
void scriptAvailable(in nsresult aResult,
void scriptAvailable(in nsresult aResult,
in nsIScriptElement aElement,
in boolean aIsInline,
in boolean aIsInlineClassicScript,
in nsIURI aURI,
in int32_t aLineNo);
@@ -40,7 +41,7 @@ interface nsIScriptLoaderObserver : nsISupports {
* @param aElement The element being processed.
* @param aIsInline Is this an inline script or externally loaded?
*/
void scriptEvaluated(in nsresult aResult,
void scriptEvaluated(in nsresult aResult,
in nsIScriptElement aElement,
in boolean aIsInline);
+1 -1
View File
@@ -137,7 +137,7 @@ SVGScriptElement::GetScriptCharset(nsAString& charset)
}
void
SVGScriptElement::FreezeUriAsyncDefer()
SVGScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc)
{
if (mFrozen) {
return;
+1 -1
View File
@@ -44,7 +44,7 @@ public:
virtual bool GetScriptType(nsAString& type) override;
virtual void GetScriptText(nsAString& text) override;
virtual void GetScriptCharset(nsAString& charset) override;
virtual void FreezeUriAsyncDefer() override;
virtual void FreezeExecutionAttrs(nsIDocument* aOwnerDoc) override;
virtual CORSMode GetCORSMode() const override;
// ScriptElement
+3 -1
View File
@@ -271,9 +271,11 @@ SVGStyleElement::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
nsAutoString title;
GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
+2 -1
View File
@@ -95,7 +95,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
virtual CORSMode GetCORSMode() const override;
/**
+1 -1
View File
@@ -13,7 +13,7 @@
// http://www.whatwg.org/specs/web-apps/current-work/#the-link-element
interface HTMLLinkElement : HTMLElement {
[Pure]
[SetterThrows, Pure]
attribute boolean disabled;
[SetterThrows, Pure]
attribute DOMString href;
+1 -1
View File
@@ -38,7 +38,7 @@ interface Node : EventTarget {
readonly attribute boolean isConnected;
[Pure]
readonly attribute Document? ownerDocument;
[Pure]
[Pure, Pref="dom.getRootNode.enabled"]
Node getRootNode(optional GetRootNodeOptions options);
[Pure]
readonly attribute Node? parentNode;
@@ -131,13 +131,15 @@ XMLStylesheetProcessingInstruction::GetStyleSheetInfo(nsAString& aTitle,
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate)
bool* aIsAlternate,
bool* aIsExplicitlyEnabled)
{
aTitle.Truncate();
aType.Truncate();
aMedia.Truncate();
*aIsScoped = false;
*aIsAlternate = false;
*aIsExplicitlyEnabled = false;
// xml-stylesheet PI is special only in prolog
if (!nsContentUtils::InProlog(this)) {
+2 -1
View File
@@ -82,7 +82,8 @@ protected:
nsAString& aType,
nsAString& aMedia,
bool* aIsScoped,
bool* aIsAlternate) override;
bool* aIsAlternate,
bool* aIsExplicitlyEnabled) override;
virtual nsGenericDOMDataNode* CloneDataNode(mozilla::dom::NodeInfo *aNodeInfo,
bool aCloneText) const override;
};
+1 -1
View File
@@ -955,7 +955,7 @@ NS_IMPL_ISUPPORTS(txTransformNotifier,
NS_IMETHODIMP
txTransformNotifier::ScriptAvailable(nsresult aResult,
nsIScriptElement *aElement,
bool aIsInline,
bool aIsInlineClassicScript,
nsIURI *aURI,
int32_t aLineNo)
{
+139 -120
View File
@@ -319,6 +319,15 @@ bool
CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute)
{
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEditableProperty(aNode, aProperty, attribute);
}
bool
CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsIAtom* aProperty,
nsIAtom* aAttribute)
{
MOZ_ASSERT(aNode);
@@ -336,13 +345,12 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
nsGkAtoms::u == aProperty ||
nsGkAtoms::strike == aProperty ||
(nsGkAtoms::font == aProperty && aAttribute &&
(aAttribute->EqualsLiteral("color") ||
aAttribute->EqualsLiteral("face")))) {
(aAttribute == nsGkAtoms::color || aAttribute == nsGkAtoms::face))) {
return true;
}
// ALIGN attribute on elements supporting it
if (aAttribute && (aAttribute->EqualsLiteral("align")) &&
if (aAttribute == nsGkAtoms::align &&
node->IsAnyOfHTMLElements(nsGkAtoms::div,
nsGkAtoms::p,
nsGkAtoms::h1,
@@ -365,7 +373,7 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
return true;
}
if (aAttribute && (aAttribute->EqualsLiteral("valign")) &&
if (aAttribute == nsGkAtoms::valign &&
node->IsAnyOfHTMLElements(nsGkAtoms::col,
nsGkAtoms::colgroup,
nsGkAtoms::tbody,
@@ -378,59 +386,52 @@ CSSEditUtils::IsCSSEditableProperty(nsINode* aNode,
}
// attributes TEXT, BACKGROUND and BGCOLOR on BODY
if (aAttribute && node->IsHTMLElement(nsGkAtoms::body) &&
(aAttribute->EqualsLiteral("text")
|| aAttribute->EqualsLiteral("background")
|| aAttribute->EqualsLiteral("bgcolor"))) {
if (node->IsHTMLElement(nsGkAtoms::body) &&
(aAttribute == nsGkAtoms::text || aAttribute == nsGkAtoms::background ||
aAttribute == nsGkAtoms::bgcolor)) {
return true;
}
// attribute BGCOLOR on other elements
if (aAttribute && aAttribute->EqualsLiteral("bgcolor")) {
if (aAttribute == nsGkAtoms::bgcolor) {
return true;
}
// attributes HEIGHT, WIDTH and NOWRAP on TD and TH
if (aAttribute &&
node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
(aAttribute->EqualsLiteral("height")
|| aAttribute->EqualsLiteral("width")
|| aAttribute->EqualsLiteral("nowrap"))) {
if (node->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th) &&
(aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::nowrap)) {
return true;
}
// attributes HEIGHT and WIDTH on TABLE
if (aAttribute && node->IsHTMLElement(nsGkAtoms::table) &&
(aAttribute->EqualsLiteral("height")
|| aAttribute->EqualsLiteral("width"))) {
if (node->IsHTMLElement(nsGkAtoms::table) &&
(aAttribute == nsGkAtoms::height || aAttribute == nsGkAtoms::width)) {
return true;
}
// attributes SIZE and WIDTH on HR
if (aAttribute && node->IsHTMLElement(nsGkAtoms::hr) &&
(aAttribute->EqualsLiteral("size")
|| aAttribute->EqualsLiteral("width"))) {
if (node->IsHTMLElement(nsGkAtoms::hr) &&
(aAttribute == nsGkAtoms::size || aAttribute == nsGkAtoms::width)) {
return true;
}
// attribute TYPE on OL UL LI
if (aAttribute &&
node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
if (node->IsAnyOfHTMLElements(nsGkAtoms::ol, nsGkAtoms::ul,
nsGkAtoms::li) &&
aAttribute->EqualsLiteral("type")) {
aAttribute == nsGkAtoms::type) {
return true;
}
if (aAttribute && node->IsHTMLElement(nsGkAtoms::img) &&
(aAttribute->EqualsLiteral("border")
|| aAttribute->EqualsLiteral("width")
|| aAttribute->EqualsLiteral("height"))) {
if (node->IsHTMLElement(nsGkAtoms::img) &&
(aAttribute == nsGkAtoms::border || aAttribute == nsGkAtoms::width ||
aAttribute == nsGkAtoms::height)) {
return true;
}
// other elements that we can align using CSS even if they
// can't carry the html ALIGN attribute
if (aAttribute && aAttribute->EqualsLiteral("align") &&
if (aAttribute == nsGkAtoms::align &&
node->IsAnyOfHTMLElements(nsGkAtoms::ul,
nsGkAtoms::ol,
nsGkAtoms::dl,
@@ -815,7 +816,7 @@ void
CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
nsTArray<nsIAtom*>& cssPropertyArray,
nsTArray<nsString>& cssValueArray,
@@ -835,21 +836,20 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
} else if (nsGkAtoms::tt == aHTMLProperty) {
equivTable = ttEquivTable;
} else if (aAttribute) {
if (nsGkAtoms::font == aHTMLProperty &&
aAttribute->EqualsLiteral("color")) {
if (nsGkAtoms::font == aHTMLProperty && aAttribute == nsGkAtoms::color) {
equivTable = fontColorEquivTable;
} else if (nsGkAtoms::font == aHTMLProperty &&
aAttribute->EqualsLiteral("face")) {
aAttribute == nsGkAtoms::face) {
equivTable = fontFaceEquivTable;
} else if (aAttribute->EqualsLiteral("bgcolor")) {
} else if (aAttribute == nsGkAtoms::bgcolor) {
equivTable = bgcolorEquivTable;
} else if (aAttribute->EqualsLiteral("background")) {
} else if (aAttribute == nsGkAtoms::background) {
equivTable = backgroundImageEquivTable;
} else if (aAttribute->EqualsLiteral("text")) {
} else if (aAttribute == nsGkAtoms::text) {
equivTable = textColorEquivTable;
} else if (aAttribute->EqualsLiteral("border")) {
} else if (aAttribute == nsGkAtoms::border) {
equivTable = borderEquivTable;
} else if (aAttribute->EqualsLiteral("align")) {
} else if (aAttribute == nsGkAtoms::align) {
if (aElement->IsHTMLElement(nsGkAtoms::table)) {
equivTable = tableAlignEquivTable;
} else if (aElement->IsHTMLElement(nsGkAtoms::hr)) {
@@ -860,17 +860,17 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
} else {
equivTable = textAlignEquivTable;
}
} else if (aAttribute->EqualsLiteral("valign")) {
} else if (aAttribute == nsGkAtoms::valign) {
equivTable = verticalAlignEquivTable;
} else if (aAttribute->EqualsLiteral("nowrap")) {
} else if (aAttribute == nsGkAtoms::nowrap) {
equivTable = nowrapEquivTable;
} else if (aAttribute->EqualsLiteral("width")) {
} else if (aAttribute == nsGkAtoms::width) {
equivTable = widthEquivTable;
} else if (aAttribute->EqualsLiteral("height") ||
} else if (aAttribute == nsGkAtoms::height ||
(aElement->IsHTMLElement(nsGkAtoms::hr) &&
aAttribute->EqualsLiteral("size"))) {
aAttribute == nsGkAtoms::size)) {
equivTable = heightEquivTable;
} else if (aAttribute->EqualsLiteral("type") &&
} else if (aAttribute == nsGkAtoms::type &&
aElement->IsAnyOfHTMLElements(nsGkAtoms::ol,
nsGkAtoms::ul,
nsGkAtoms::li)) {
@@ -887,40 +887,46 @@ CSSEditUtils::GenerateCSSDeclarationsFromHTMLStyle(
// aValue for the node, and return in aCount the number of CSS properties set
// by the call. The Element version returns aCount instead.
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement && aProperty);
MOZ_ASSERT_IF(aAttribute, aValue);
int32_t count;
// This can only fail if SetCSSProperty fails, which should only happen if
// something is pretty badly wrong. In this case we assert so that hopefully
// someone will notice, but there's nothing more sensible to do than just
// return the count and carry on.
nsresult rv = SetCSSEquivalentToHTMLStyle(aElement->AsDOMNode(),
aProperty, aAttribute,
aValue, &count,
aSuppressTransaction);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetCSSEquivalentToHTMLStyle failed");
NS_ENSURE_SUCCESS(rv, count);
return count;
nsCOMPtr<Element> element = do_QueryInterface(aNode);
return SetCSSEquivalentToHTMLStyle(element,
aProperty, aAttribute,
aValue, aSuppressTransaction);
}
nsresult
CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
int32_t* aCount,
bool aSuppressTransaction)
{
nsCOMPtr<Element> element = do_QueryInterface(aNode);
*aCount = 0;
if (!element || !IsCSSEditableProperty(element, aHTMLProperty, aAttribute)) {
return NS_OK;
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return SetCSSEquivalentToHTMLStyle(aElement, aHTMLProperty, attribute,
aValue, aSuppressTransaction);
}
int32_t
CSSEditUtils::SetCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
return 0;
}
// we can apply the styles only if the node is an element and if we have
@@ -929,18 +935,20 @@ CSSEditUtils::SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
// Find the CSS equivalence to the HTML style
nsTArray<nsIAtom*> cssPropertyArray;
nsTArray<nsString> cssValueArray;
GenerateCSSDeclarationsFromHTMLStyle(element, aHTMLProperty, aAttribute,
GenerateCSSDeclarationsFromHTMLStyle(aElement, aHTMLProperty, aAttribute,
aValue, cssPropertyArray, cssValueArray,
false);
// set the individual CSS inline styles
*aCount = cssPropertyArray.Length();
for (int32_t index = 0; index < *aCount; index++) {
nsresult rv = SetCSSProperty(*element, *cssPropertyArray[index],
size_t count = cssPropertyArray.Length();
for (size_t index = 0; index < count; index++) {
nsresult rv = SetCSSProperty(*aElement, *cssPropertyArray[index],
cssValueArray[index], aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return 0;
}
}
return NS_OK;
return count;
}
// Remove from aNode the CSS inline style equivalent to HTMLProperty/aAttribute/aValue for the node
@@ -952,20 +960,22 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
bool aSuppressTransaction)
{
nsCOMPtr<Element> element = do_QueryInterface(aNode);
NS_ENSURE_TRUE(element, NS_OK);
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, aAttribute,
return RemoveCSSEquivalentToHTMLStyle(element, aHTMLProperty, attribute,
aValue, aSuppressTransaction);
}
nsresult
CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
if (NS_WARN_IF(!aElement)) {
return NS_OK;
}
if (!IsCSSEditableProperty(aElement, aHTMLProperty, aAttribute)) {
return NS_OK;
@@ -1000,7 +1010,7 @@ CSSEditUtils::RemoveCSSEquivalentToHTMLStyle(Element* aElement,
nsresult
CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
nsAString& aValueString,
StyleType aStyleType)
{
@@ -1017,7 +1027,8 @@ CSSEditUtils::GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsTArray<nsString> cssValueArray;
// get the CSS equivalence with last param true indicating we want only the
// "gettable" properties
GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute, nullptr,
GenerateCSSDeclarationsFromHTMLStyle(theElement, aHTMLProperty, aAttribute,
nullptr,
cssPropertyArray, cssValueArray, true);
int32_t count = cssPropertyArray.Length();
for (int32_t index = 0; index < count; index++) {
@@ -1063,48 +1074,58 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
StyleType aStyleType)
{
MOZ_ASSERT(aNode && aProperty);
bool isSet;
nsresult rv = IsCSSEquivalentToHTMLInlineStyleSet(aNode->AsDOMNode(),
aProperty, aAttribute,
isSet, aValue, aStyleType);
NS_ENSURE_SUCCESS(rv, false);
return isSet;
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEquivalentToHTMLInlineStyleSet(aNode,
aProperty, attribute,
aValue, aStyleType);
}
nsresult
bool
CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
nsAString& aValue,
StyleType aStyleType)
{
MOZ_ASSERT(aNode && aProperty);
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
nsCOMPtr<nsIAtom> attribute = aAttribute ? NS_Atomize(*aAttribute) : nullptr;
return IsCSSEquivalentToHTMLInlineStyleSet(node, aProperty, attribute,
aValue, aStyleType);
}
bool
CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
nsIDOMNode* aNode,
nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aHTMLAttribute,
bool& aIsSet,
nsIAtom* aHTMLAttribute,
nsAString& valueString,
StyleType aStyleType)
{
NS_ENSURE_TRUE(aNode, NS_ERROR_NULL_POINTER);
NS_ENSURE_TRUE(aNode, false);
nsAutoString htmlValueString(valueString);
aIsSet = false;
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
bool isSet = false;
do {
valueString.Assign(htmlValueString);
// get the value of the CSS equivalent styles
nsresult rv =
GetCSSEquivalentToHTMLInlineStyleSet(node, aHTMLProperty, aHTMLAttribute,
GetCSSEquivalentToHTMLInlineStyleSet(aNode, aHTMLProperty, aHTMLAttribute,
valueString, aStyleType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_SUCCESS(rv, false);
// early way out if we can
if (valueString.IsEmpty()) {
return NS_OK;
return isSet;
}
if (nsGkAtoms::b == aHTMLProperty) {
if (valueString.EqualsLiteral("bold")) {
aIsSet = true;
isSet = true;
} else if (valueString.EqualsLiteral("normal")) {
aIsSet = false;
isSet = false;
} else if (valueString.EqualsLiteral("bolder")) {
aIsSet = true;
isSet = true;
valueString.AssignLiteral("bold");
} else {
int32_t weight = 0;
@@ -1112,32 +1133,31 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
nsAutoString value(valueString);
weight = value.ToInteger(&errorCode);
if (400 < weight) {
aIsSet = true;
isSet = true;
valueString.AssignLiteral("bold");
} else {
aIsSet = false;
isSet = false;
valueString.AssignLiteral("normal");
}
}
} else if (nsGkAtoms::i == aHTMLProperty) {
if (valueString.EqualsLiteral("italic") ||
valueString.EqualsLiteral("oblique")) {
aIsSet = true;
isSet = true;
}
} else if (nsGkAtoms::u == aHTMLProperty) {
nsAutoString val;
val.AssignLiteral("underline");
aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if (nsGkAtoms::strike == aHTMLProperty) {
nsAutoString val;
val.AssignLiteral("line-through");
aIsSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if (aHTMLAttribute &&
((nsGkAtoms::font == aHTMLProperty &&
aHTMLAttribute->EqualsLiteral("color")) ||
aHTMLAttribute->EqualsLiteral("bgcolor"))) {
isSet = ChangeStyleTransaction::ValueIncludes(valueString, val);
} else if ((nsGkAtoms::font == aHTMLProperty &&
aHTMLAttribute == nsGkAtoms::color) ||
aHTMLAttribute == nsGkAtoms::bgcolor) {
if (htmlValueString.IsEmpty()) {
aIsSet = true;
isSet = true;
} else {
nscolor rgba;
nsAutoString subStr;
@@ -1171,54 +1191,53 @@ CSSEditUtils::IsCSSEquivalentToHTMLInlineStyleSet(
htmlColor.Append(char16_t(')'));
}
aIsSet = htmlColor.Equals(valueString,
nsCaseInsensitiveStringComparator());
isSet = htmlColor.Equals(valueString,
nsCaseInsensitiveStringComparator());
} else {
aIsSet = htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator());
isSet = htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator());
}
}
} else if (nsGkAtoms::tt == aHTMLProperty) {
aIsSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
isSet = StringBeginsWith(valueString, NS_LITERAL_STRING("monospace"));
} else if (nsGkAtoms::font == aHTMLProperty && aHTMLAttribute &&
aHTMLAttribute->EqualsLiteral("face")) {
aHTMLAttribute == nsGkAtoms::face) {
if (!htmlValueString.IsEmpty()) {
const char16_t commaSpace[] = { char16_t(','), char16_t(' '), 0 };
const char16_t comma[] = { char16_t(','), 0 };
htmlValueString.ReplaceSubstring(commaSpace, comma);
nsAutoString valueStringNorm(valueString);
valueStringNorm.ReplaceSubstring(commaSpace, comma);
aIsSet = htmlValueString.Equals(valueStringNorm,
nsCaseInsensitiveStringComparator());
isSet = htmlValueString.Equals(valueStringNorm,
nsCaseInsensitiveStringComparator());
} else {
aIsSet = true;
isSet = true;
}
return NS_OK;
} else if (aHTMLAttribute && aHTMLAttribute->EqualsLiteral("align")) {
aIsSet = true;
return isSet;
} else if (aHTMLAttribute == nsGkAtoms::align) {
isSet = true;
} else {
aIsSet = false;
return NS_OK;
return false;
}
if (!htmlValueString.IsEmpty() &&
htmlValueString.Equals(valueString,
nsCaseInsensitiveStringComparator())) {
aIsSet = true;
isSet = true;
}
if (htmlValueString.EqualsLiteral("-moz-editor-invert-value")) {
aIsSet = !aIsSet;
isSet = !isSet;
}
if (nsGkAtoms::u == aHTMLProperty || nsGkAtoms::strike == aHTMLProperty) {
// unfortunately, the value of the text-decoration property is not inherited.
// that means that we have to look at ancestors of node to see if they are underlined
node = node->GetParentElement(); // set to null if it's not a dom element
aNode = aNode->GetParentElement(); // set to null if it's not a dom element
}
} while ((nsGkAtoms::u == aHTMLProperty ||
nsGkAtoms::strike == aHTMLProperty) && !aIsSet && node);
return NS_OK;
nsGkAtoms::strike == aHTMLProperty) && !isSet && aNode);
return isSet;
}
void
+36 -29
View File
@@ -90,6 +90,8 @@ public:
*/
bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty,
const nsAString* aAttribute);
bool IsCSSEditableProperty(nsINode* aNode, nsIAtom* aProperty,
nsIAtom* aAttribute);
/**
* Adds/remove a CSS declaration to the STYLE atrribute carried by a given
@@ -188,14 +190,14 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* @param aAttribute [IN] An atom of attribute name or nullptr if
* irrelevant.
* @param aValueString [OUT] The list of CSS values.
* @param aStyleType [IN] eSpecified or eComputed.
*/
nsresult GetCSSEquivalentToHTMLInlineStyleSet(nsINode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
nsAString& aValueString,
StyleType aStyleType);
@@ -205,16 +207,20 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* irrelevant.
* @param aIsSet [OUT] A boolean being true if the css properties are
* set.
* @param aAttribute [IN] A pointer/atom to an attribute name or nullptr
* if irrelevant.
* @param aValueString [IN/OUT] The attribute value (in) the list of CSS
* values (out).
* @param aStyleType [IN] eSpecified or eComputed.
*
* The nsIContent variant returns aIsSet instead of using an out parameter.
* @return A boolean being true if the css properties are
* set.
*/
bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent,
nsIAtom* aProperty,
nsIAtom* aAttribute,
nsAString& aValue,
StyleType aStyleType);
bool IsCSSEquivalentToHTMLInlineStyleSet(nsINode* aContent,
nsIAtom* aProperty,
const nsAString* aAttribute,
@@ -227,12 +233,11 @@ public:
nsAString& aValue,
StyleType aStyleType);
nsresult IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
bool& aIsSet,
nsAString& aValueString,
StyleType aStyleType);
bool IsCSSEquivalentToHTMLInlineStyleSet(nsIDOMNode* aNode,
nsIAtom* aProperty,
const nsAString* aAttribute,
nsAString& aValue,
StyleType aStyleType);
/**
* Adds to the node the CSS inline styles equivalent to the HTML style
@@ -240,27 +245,29 @@ public:
*
* @param aNode [IN] A DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* irrelevant.
* @param aAttribute [IN] A pointer/atom to an attribute name or nullptr
* if irrelevant.
* @param aValue [IN] The attribute value.
* @param aCount [OUT] The number of CSS properties set by the call.
* @param aSuppressTransaction [IN] A boolean indicating, when true,
* that no transaction should be recorded.
*
* aCount is returned by the dom::Element variant instead of being an out
* parameter.
* @return The number of CSS properties set by the call.
*/
int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aProperty,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
int32_t SetCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
nsresult SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
int32_t* aCount,
bool aSuppressTransaction);
int32_t SetCSSEquivalentToHTMLStyle(nsIDOMNode* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
/**
* Removes from the node the CSS inline styles equivalent to the HTML style.
@@ -284,7 +291,7 @@ public:
*
* @param aElement [IN] A DOM Element (must not be null).
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr if
* @param aAttribute [IN] An atom to an attribute name or nullptr if
* irrelevant.
* @param aValue [IN] The attribute value.
* @param aSuppressTransaction [IN] A boolean indicating, when true,
@@ -292,7 +299,7 @@ public:
*/
nsresult RemoveCSSEquivalentToHTMLStyle(dom::Element* aElement,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
bool aSuppressTransaction);
@@ -409,7 +416,7 @@ private:
*
* @param aNode [IN] The DOM node.
* @param aHTMLProperty [IN] An atom containing an HTML property.
* @param aAttribute [IN] A pointer to an attribute name or nullptr
* @param aAttribute [IN] An atom to an attribute name or nullptr
* if irrelevant
* @param aValue [IN] The attribute value.
* @param aPropertyArray [OUT] The array of CSS properties.
@@ -422,7 +429,7 @@ private:
*/
void GenerateCSSDeclarationsFromHTMLStyle(dom::Element* aNode,
nsIAtom* aHTMLProperty,
const nsAString* aAttribute,
nsIAtom* aAttribute,
const nsAString* aValue,
nsTArray<nsIAtom*>& aPropertyArray,
nsTArray<nsString>& aValueArray,
+64 -31
View File
@@ -1229,12 +1229,23 @@ EditorBase::SetAttribute(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue)
{
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return SetAttribute(element, attribute, aValue);
}
nsresult
EditorBase::SetAttribute(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue)
{
RefPtr<ChangeAttributeTransaction> transaction =
CreateTxnForSetAttribute(*element, *attribute, aValue);
CreateTxnForSetAttribute(*aElement, *aAttribute, aValue);
return DoTransaction(transaction);
}
@@ -1263,12 +1274,22 @@ NS_IMETHODIMP
EditorBase::RemoveAttribute(nsIDOMElement* aElement,
const nsAString& aAttribute)
{
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return RemoveAttribute(element, attribute);
}
nsresult
EditorBase::RemoveAttribute(Element* aElement,
nsIAtom* aAttribute)
{
RefPtr<ChangeAttributeTransaction> transaction =
CreateTxnForRemoveAttribute(*element, *attribute);
CreateTxnForRemoveAttribute(*aElement, *aAttribute);
return DoTransaction(transaction);
}
@@ -2208,25 +2229,28 @@ EditorBase::CloneAttribute(const nsAString& aAttribute,
nsIDOMNode* aSourceNode)
{
NS_ENSURE_TRUE(aDestNode && aSourceNode, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIDOMElement> destElement = do_QueryInterface(aDestNode);
nsCOMPtr<nsIDOMElement> sourceElement = do_QueryInterface(aSourceNode);
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
nsAutoString attrValue;
bool isAttrSet;
nsresult rv = GetAttributeValue(sourceElement,
aAttribute,
attrValue,
&isAttrSet);
NS_ENSURE_SUCCESS(rv, rv);
if (isAttrSet) {
rv = SetAttribute(destElement, aAttribute, attrValue);
} else {
rv = RemoveAttribute(destElement, aAttribute);
if (NS_WARN_IF(aAttribute.IsEmpty())) {
return NS_ERROR_FAILURE;
}
return rv;
nsCOMPtr<Element> destElement = do_QueryInterface(aDestNode);
nsCOMPtr<Element> sourceElement = do_QueryInterface(aSourceNode);
NS_ENSURE_TRUE(destElement && sourceElement, NS_ERROR_NO_INTERFACE);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return CloneAttribute(attribute, destElement, sourceElement);
}
nsresult
EditorBase::CloneAttribute(nsIAtom* aAttribute,
Element* aDestElement,
Element* aSourceElement)
{
nsAutoString attrValue;
if (aSourceElement->GetAttr(kNameSpaceID_None, aAttribute, attrValue)) {
return SetAttribute(aDestElement, aAttribute, attrValue);
}
return RemoveAttribute(aDestElement, aAttribute);
}
/**
@@ -2265,11 +2289,9 @@ EditorBase::CloneAttributes(Element* aDest,
RefPtr<nsDOMAttributeMap> destAttributes = aDest->Attributes();
while (RefPtr<Attr> attr = destAttributes->Item(0)) {
if (destInBody) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName());
RemoveAttribute(aDest, attr->NodeInfo()->NameAtom());
} else {
ErrorResult ignored;
aDest->RemoveAttribute(attr->NodeName(), ignored);
aDest->UnsetAttr(kNameSpaceID_None, attr->NodeInfo()->NameAtom(), true);
}
}
@@ -2281,13 +2303,13 @@ EditorBase::CloneAttributes(Element* aDest,
nsAutoString value;
attr->GetValue(value);
if (destInBody) {
SetAttributeOrEquivalent(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName(), value, false);
SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value,
false);
} else {
// The element is not inserted in the document yet, we don't want to put
// a transaction on the UndoStack
SetAttributeOrEquivalent(static_cast<nsIDOMElement*>(GetAsDOMNode(aDest)),
attr->NodeName(), value, true);
SetAttributeOrEquivalent(aDest, attr->NodeInfo()->NameAtom(), value,
true);
}
}
}
@@ -4618,21 +4640,32 @@ EditorBase::CreateHTMLContent(nsIAtom* aTag)
kNameSpaceID_XHTML);
}
nsresult
NS_IMETHODIMP
EditorBase::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
return SetAttribute(aElement, aAttribute, aValue);
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (NS_WARN_IF(!element)) {
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return SetAttributeOrEquivalent(element, attribute, aValue,
aSuppressTransaction);
}
nsresult
NS_IMETHODIMP
EditorBase::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction)
{
return RemoveAttribute(aElement, aAttribute);
nsCOMPtr<Element> element = do_QueryInterface(aElement);
if (NS_WARN_IF(!element)) {
return NS_ERROR_NULL_POINTER;
}
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
return RemoveAttributeOrEquivalent(element, attribute, aSuppressTransaction);
}
nsresult
+13
View File
@@ -236,6 +236,19 @@ public:
nsresult JoinNodes(nsINode& aLeftNode, nsINode& aRightNode);
nsresult MoveNode(nsIContent* aNode, nsINode* aParent, int32_t aOffset);
nsresult CloneAttribute(nsIAtom* aAttribute, Element* aDestElement,
Element* aSourceElement);
nsresult RemoveAttribute(Element* aElement, nsIAtom* aAttribute);
virtual nsresult RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) = 0;
nsresult SetAttribute(Element* aElement, nsIAtom* aAttribute,
const nsAString& aValue);
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) = 0;
/**
* Method to replace certain CreateElementNS() calls.
*
+42 -41
View File
@@ -839,19 +839,18 @@ HTMLEditRules::GetAlignment(bool* aMixed,
NS_ENSURE_TRUE(nodeToExamine, NS_ERROR_NULL_POINTER);
NS_NAMED_LITERAL_STRING(typeAttrName, "align");
nsCOMPtr<Element> blockParent = htmlEditor->GetBlock(*nodeToExamine);
NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
if (htmlEditor->IsCSSEnabled() &&
htmlEditor->mCSSEditUtils->IsCSSEditableProperty(blockParent, nullptr,
&typeAttrName)) {
nsGkAtoms::align)) {
// We are in CSS mode and we know how to align this element with CSS
nsAutoString value;
// Let's get the value(s) of text-align or margin-left/margin-right
htmlEditor->mCSSEditUtils->GetCSSEquivalentToHTMLInlineStyleSet(
blockParent, nullptr, &typeAttrName, value, CSSEditUtils::eComputed);
blockParent, nullptr, nsGkAtoms::align, value, CSSEditUtils::eComputed);
if (value.EqualsLiteral("center") ||
value.EqualsLiteral("-moz-center") ||
value.EqualsLiteral("auto auto")) {
@@ -1510,10 +1509,11 @@ HTMLEditRules::WillInsertBreak(Selection& aSelection,
nsCOMPtr<Element> blockParent = htmlEditor->GetBlock(node);
NS_ENSURE_TRUE(blockParent, NS_ERROR_FAILURE);
// If the active editing host is an inline element, or if the active editing
// host is the block parent itself, just append a br.
// When there is an active editing host (the <body> if it's in designMode)
// and a block which becomes the parent of line breaker is in it, do the
// standard thing.
nsCOMPtr<Element> host = htmlEditor->GetActiveEditingHost();
if (!EditorUtils::IsDescendantOf(blockParent, host)) {
if (host && !EditorUtils::IsDescendantOf(blockParent, host)) {
nsresult rv = StandardBreakImpl(node, offset, aSelection);
NS_ENSURE_SUCCESS(rv, rv);
*aHandled = true;
@@ -3303,15 +3303,15 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
}
}
NS_ENSURE_STATE(mHTMLEditor);
nsCOMPtr<nsIDOMElement> curElement = do_QueryInterface(curNode);
NS_NAMED_LITERAL_STRING(typestr, "type");
nsCOMPtr<Element> curElement = do_QueryInterface(curNode);
if (aBulletType && !aBulletType->IsEmpty()) {
rv = mHTMLEditor->SetAttribute(curElement, typestr, *aBulletType);
rv = mHTMLEditor->SetAttribute(curElement, nsGkAtoms::type,
*aBulletType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
rv = mHTMLEditor->RemoveAttribute(curElement, typestr);
rv = mHTMLEditor->RemoveAttribute(curElement, nsGkAtoms::type);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -4755,7 +4755,7 @@ HTMLEditRules::WillAlign(Selection& aSelection,
NS_ENSURE_SUCCESS(rv, rv);
if (useCSS) {
htmlEditor->mCSSEditUtils->SetCSSEquivalentToHTMLStyle(
curNode->AsElement(), nullptr, &NS_LITERAL_STRING("align"),
curNode->AsElement(), nullptr, nsGkAtoms::align,
&aAlignType, false);
curDiv = nullptr;
continue;
@@ -4836,7 +4836,6 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
NS_ENSURE_TRUE(node && alignType, NS_ERROR_NULL_POINTER);
nsCOMPtr<nsIContent> firstChild, lastChild;
nsCOMPtr<Element> divNode;
bool useCSS = mHTMLEditor->IsCSSEnabled();
@@ -4844,24 +4843,25 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
firstChild = mHTMLEditor->GetFirstEditableChild(*node);
NS_ENSURE_STATE(mHTMLEditor);
lastChild = mHTMLEditor->GetLastEditableChild(*node);
NS_NAMED_LITERAL_STRING(attr, "align");
if (!firstChild) {
// this cell has no content, nothing to align
} else if (firstChild == lastChild &&
firstChild->IsHTMLElement(nsGkAtoms::div)) {
// the cell already has a div containing all of its content: just
// act on this div.
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(firstChild);
RefPtr<Element> divElem = firstChild->AsElement();
if (useCSS) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem, attr,
nsresult rv = mHTMLEditor->SetAttributeOrEquivalent(divElem,
nsGkAtoms::align,
*alignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
nsresult rv = mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align,
*alignType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -4869,28 +4869,29 @@ HTMLEditRules::AlignBlockContents(nsIDOMNode* aNode,
} else {
// else we need to put in a div, set the alignment, and toss in all the children
NS_ENSURE_STATE(mHTMLEditor);
divNode = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0);
NS_ENSURE_STATE(divNode);
RefPtr<Element> divElem = mHTMLEditor->CreateNode(nsGkAtoms::div, node, 0);
NS_ENSURE_STATE(divElem);
// set up the alignment on the div
nsCOMPtr<nsIDOMElement> divElem = do_QueryInterface(divNode);
if (useCSS) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv =
mHTMLEditor->SetAttributeOrEquivalent(divElem, attr, *alignType, false);
mHTMLEditor->SetAttributeOrEquivalent(divElem, nsGkAtoms::align,
*alignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
} else {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->SetAttribute(divElem, attr, *alignType);
nsresult rv =
mHTMLEditor->SetAttribute(divElem, nsGkAtoms::align, *alignType);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
// tuck the children into the end of the active div
while (lastChild && (lastChild != divNode)) {
while (lastChild && (lastChild != divElem)) {
NS_ENSURE_STATE(mHTMLEditor);
nsresult rv = mHTMLEditor->MoveNode(lastChild, divNode, 0);
nsresult rv = mHTMLEditor->MoveNode(lastChild, divElem, 0);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_STATE(mHTMLEditor);
lastChild = mHTMLEditor->GetLastEditableChild(*node);
@@ -6480,10 +6481,14 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
// split the paragraph
NS_ENSURE_STATE(mHTMLEditor);
NS_ENSURE_STATE(selNode->IsContent());
mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset,
HTMLEditor::EmptyContainers::yes,
getter_AddRefs(leftPara),
getter_AddRefs(rightPara));
int32_t offset =
mHTMLEditor->SplitNodeDeep(*para, *selNode->AsContent(), *aOffset,
HTMLEditor::EmptyContainers::yes,
getter_AddRefs(leftPara),
getter_AddRefs(rightPara));
if (NS_WARN_IF(offset == -1)) {
return NS_ERROR_FAILURE;
}
// get rid of the break, if it is visible (otherwise it may be needed to prevent an empty p)
NS_ENSURE_STATE(mHTMLEditor);
if (mHTMLEditor->IsVisBreak(aBRNode)) {
@@ -6493,9 +6498,9 @@ HTMLEditRules::SplitParagraph(nsIDOMNode *aPara,
}
// remove ID attribute on the paragraph we just created
nsCOMPtr<nsIDOMElement> rightElt = do_QueryInterface(rightPara);
RefPtr<Element> rightElt = rightPara->AsElement();
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->RemoveAttribute(rightElt, NS_LITERAL_STRING("id"));
rv = mHTMLEditor->RemoveAttribute(rightElt, nsGkAtoms::id);
NS_ENSURE_SUCCESS(rv, rv);
// check both halves of para to see if we need mozBR
@@ -7125,9 +7130,9 @@ HTMLEditRules::CacheInlineStyles(nsIDOMNode* aNode)
isSet, &outValue);
} else {
NS_ENSURE_STATE(mHTMLEditor);
mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(aNode,
mCachedStyles[j].tag, &(mCachedStyles[j].attr), isSet, outValue,
CSSEditUtils::eComputed);
isSet = mHTMLEditor->mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(
aNode, mCachedStyles[j].tag, &(mCachedStyles[j].attr), outValue,
CSSEditUtils::eComputed);
}
if (isSet) {
mCachedStyles[j].mPresent = true;
@@ -8356,18 +8361,18 @@ HTMLEditRules::RemoveAlignment(nsIDOMNode* aNode,
NS_ENSURE_SUCCESS(rv, rv);
} else if (isBlock || HTMLEditUtils::IsHR(child)) {
// the current node is a block element
nsCOMPtr<nsIDOMElement> curElem = do_QueryInterface(child);
nsCOMPtr<Element> curElem = do_QueryInterface(child);
if (HTMLEditUtils::SupportsAlignAttr(child)) {
// remove the ALIGN attribute if this element can have it
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->RemoveAttribute(curElem, NS_LITERAL_STRING("align"));
rv = mHTMLEditor->RemoveAttribute(curElem, nsGkAtoms::align);
NS_ENSURE_SUCCESS(rv, rv);
}
if (useCSS) {
if (HTMLEditUtils::IsTable(child) || HTMLEditUtils::IsHR(child)) {
NS_ENSURE_STATE(mHTMLEditor);
rv = mHTMLEditor->SetAttributeOrEquivalent(curElem,
NS_LITERAL_STRING("align"),
nsGkAtoms::align,
aAlignType, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
@@ -8487,21 +8492,17 @@ HTMLEditRules::AlignBlock(Element& aElement,
nsresult rv = RemoveAlignment(aElement.AsDOMNode(), aAlignType,
aContentsOnly == ContentsOnly::yes);
NS_ENSURE_SUCCESS(rv, rv);
NS_NAMED_LITERAL_STRING(attr, "align");
if (htmlEditor->IsCSSEnabled()) {
// Let's use CSS alignment; we use margin-left and margin-right for tables
// and text-align for other block-level elements
rv = htmlEditor->SetAttributeOrEquivalent(
static_cast<nsIDOMElement*>(aElement.AsDOMNode()),
attr, aAlignType, false);
&aElement, nsGkAtoms::align, aAlignType, false);
NS_ENSURE_SUCCESS(rv, rv);
} else {
// HTML case; this code is supposed to be called ONLY if the element
// supports the align attribute but we'll never know...
if (HTMLEditUtils::SupportsAlignAttr(aElement.AsDOMNode())) {
rv = htmlEditor->SetAttribute(
static_cast<nsIDOMElement*>(aElement.AsDOMNode()),
attr, aAlignType);
rv = htmlEditor->SetAttribute(&aElement, nsGkAtoms::align, aAlignType);
NS_ENSURE_SUCCESS(rv, rv);
}
}
+68 -68
View File
@@ -2584,7 +2584,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
// New call to use instead to get proper HTML element, bug 39919
nsCOMPtr<nsIAtom> realTagAtom = NS_Atomize(realTagName);
nsCOMPtr<Element> newElement = CreateHTMLContent(realTagAtom);
RefPtr<Element> newElement = CreateHTMLContent(realTagAtom);
if (!newElement) {
return nullptr;
}
@@ -2616,8 +2616,7 @@ HTMLEditor::CreateElementWithDefaults(const nsAString& aTagName)
} else if (tagName.EqualsLiteral("td")) {
nsresult rv =
SetAttributeOrEquivalent(
static_cast<nsIDOMElement*>(newElement->AsDOMNode()),
NS_LITERAL_STRING("valign"), NS_LITERAL_STRING("top"), true);
newElement, nsGkAtoms::valign, NS_LITERAL_STRING("top"), true);
NS_ENSURE_SUCCESS(rv, nullptr);
}
// ADD OTHER TAGS HERE
@@ -4443,87 +4442,83 @@ HTMLEditor::IsEmptyNodeImpl(nsINode* aNode,
// add to aElement the CSS inline styles corresponding to the HTML attribute
// aAttribute with its value aValue
nsresult
HTMLEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
HTMLEditor::SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
MOZ_ASSERT(aElement);
MOZ_ASSERT(aAttribute);
nsAutoScriptBlocker scriptBlocker;
if (IsCSSEnabled() && mCSSEditUtils) {
int32_t count;
nsresult rv =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr,
&aAttribute, &aValue,
&count,
aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
if (count) {
// we found an equivalence ; let's remove the HTML attribute itself if it is set
nsAutoString existingValue;
bool wasSet = false;
rv = GetAttributeValue(aElement, aAttribute, existingValue, &wasSet);
NS_ENSURE_SUCCESS(rv, rv);
if (!wasSet) {
return NS_OK;
}
return aSuppressTransaction ? aElement->RemoveAttribute(aAttribute) :
RemoveAttribute(aElement, aAttribute);
}
// count is an integer that represents the number of CSS declarations applied to the
// element. If it is zero, we found no equivalence in this implementation for the
// attribute
if (aAttribute.EqualsLiteral("style")) {
// if it is the style attribute, just add the new value to the existing style
// attribute's value
nsAutoString existingValue;
bool wasSet = false;
nsresult rv = GetAttributeValue(aElement, NS_LITERAL_STRING("style"),
existingValue, &wasSet);
NS_ENSURE_SUCCESS(rv, rv);
existingValue.Append(' ');
existingValue.Append(aValue);
return aSuppressTransaction ?
aElement->SetAttribute(aAttribute, existingValue) :
SetAttribute(aElement, aAttribute, existingValue);
}
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) :
SetAttribute(aElement, aAttribute, aValue);
if (!IsCSSEnabled() || !mCSSEditUtils) {
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
return aSuppressTransaction ?
aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
SetAttribute(aElement, aAttribute, aValue);
}
// we are not in an HTML+CSS editor; let's set the attribute the HTML way
return aSuppressTransaction ? aElement->SetAttribute(aAttribute, aValue) :
SetAttribute(aElement, aAttribute, aValue);
int32_t count =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(aElement, nullptr,
aAttribute, &aValue,
aSuppressTransaction);
if (count) {
// we found an equivalence ; let's remove the HTML attribute itself if it
// is set
nsAutoString existingValue;
if (!aElement->GetAttr(kNameSpaceID_None, aAttribute, existingValue)) {
return NS_OK;
}
return aSuppressTransaction ?
aElement->UnsetAttr(kNameSpaceID_None, aAttribute, true) :
RemoveAttribute(aElement, aAttribute);
}
// count is an integer that represents the number of CSS declarations applied
// to the element. If it is zero, we found no equivalence in this
// implementation for the attribute
if (aAttribute == nsGkAtoms::style) {
// if it is the style attribute, just add the new value to the existing
// style attribute's value
nsAutoString existingValue;
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::style, existingValue);
existingValue.Append(' ');
existingValue.Append(aValue);
return aSuppressTransaction ?
aElement->SetAttr(kNameSpaceID_None, aAttribute, existingValue, true) :
SetAttribute(aElement, aAttribute, existingValue);
}
// we have no CSS equivalence for this attribute and it is not the style
// attribute; let's set it the good'n'old HTML way
return aSuppressTransaction ?
aElement->SetAttr(kNameSpaceID_None, aAttribute, aValue, true) :
SetAttribute(aElement, aAttribute, aValue);
}
nsresult
HTMLEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
HTMLEditor::RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction)
{
nsCOMPtr<dom::Element> element = do_QueryInterface(aElement);
NS_ENSURE_TRUE(element, NS_OK);
nsCOMPtr<nsIAtom> attribute = NS_Atomize(aAttribute);
MOZ_ASSERT(attribute);
MOZ_ASSERT(aElement);
MOZ_ASSERT(aAttribute);
if (IsCSSEnabled() && mCSSEditUtils) {
nsresult rv =
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(
element, nullptr, &aAttribute, nullptr, aSuppressTransaction);
aElement, nullptr, aAttribute, nullptr, aSuppressTransaction);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!element->HasAttr(kNameSpaceID_None, attribute)) {
if (!aElement->HasAttr(kNameSpaceID_None, aAttribute)) {
return NS_OK;
}
return aSuppressTransaction ?
element->UnsetAttr(kNameSpaceID_None, attribute, /* aNotify = */ true) :
aElement->UnsetAttr(kNameSpaceID_None, aAttribute, /* aNotify = */ true) :
RemoveAttribute(aElement, aAttribute);
}
@@ -4576,7 +4571,6 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
NS_ENSURE_SUCCESS(rv, rv);
if (!cancel && !handled) {
// Loop through the ranges in the selection
NS_NAMED_LITERAL_STRING(bgcolor, "bgcolor");
for (uint32_t i = 0; i < selection->RangeCount(); i++) {
RefPtr<nsRange> range = selection->GetRangeAt(i);
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
@@ -4595,13 +4589,15 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor, false);
nsGkAtoms::bgcolor,
&aColor, false);
}
} else if (startNode == endNode &&
startNode->IsHTMLElement(nsGkAtoms::body) && isCollapsed) {
// No block in the document, let's apply the background to the body
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(startNode->AsElement(),
nullptr, &bgcolor, &aColor,
nullptr, nsGkAtoms::bgcolor,
&aColor,
false);
} else if (startNode == endNode && (endOffset - startOffset == 1 ||
(!startOffset && !endOffset))) {
@@ -4612,7 +4608,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor, false);
nsGkAtoms::bgcolor,
&aColor, false);
}
} else {
// Not the easy case. Range not contained in single text node. There
@@ -4655,7 +4652,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}
@@ -4666,7 +4664,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}
@@ -4680,7 +4679,8 @@ HTMLEditor::SetCSSBackgroundColor(const nsAString& aColor)
if (blockParent && cachedBlockParent != blockParent) {
cachedBlockParent = blockParent;
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(blockParent, nullptr,
&bgcolor, &aColor,
nsGkAtoms::bgcolor,
&aColor,
false);
}
}
+10 -8
View File
@@ -118,6 +118,16 @@ public:
virtual already_AddRefed<nsIContent> GetInputEventTargetContent() override;
virtual bool IsEditable(nsINode* aNode) override;
using EditorBase::IsEditable;
virtual nsresult RemoveAttributeOrEquivalent(
Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) override;
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
using EditorBase::RemoveAttributeOrEquivalent;
using EditorBase::SetAttributeOrEquivalent;
// nsStubMutationObserver overrides
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
@@ -329,14 +339,6 @@ public:
*/
virtual nsresult SelectEntireDocument(Selection* aSelection) override;
NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction) override;
/**
* Join together any adjacent editable text nodes in the range.
*/
+12 -17
View File
@@ -926,35 +926,30 @@ HTMLEditor::SetFinalSize(int32_t aX,
// we want one transaction only from a user's point of view
AutoEditBatch batchIt(this);
NS_NAMED_LITERAL_STRING(widthStr, "width");
NS_NAMED_LITERAL_STRING(heightStr, "height");
nsCOMPtr<Element> resizedObject = do_QueryInterface(mResizedObject);
NS_ENSURE_TRUE(resizedObject, );
if (mResizedObjectIsAbsolutelyPositioned) {
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::top, y);
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::top, y);
}
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::left, x);
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::left, x);
}
}
if (IsCSSEnabled() || mResizedObjectIsAbsolutelyPositioned) {
if (setWidth && mResizedObject->HasAttr(kNameSpaceID_None, nsGkAtoms::width)) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), widthStr);
RemoveAttribute(mResizedObject, nsGkAtoms::width);
}
if (setHeight && mResizedObject->HasAttr(kNameSpaceID_None,
nsGkAtoms::height)) {
RemoveAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), heightStr);
RemoveAttribute(mResizedObject, nsGkAtoms::height);
}
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width,
width);
}
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height,
height);
}
} else {
@@ -964,30 +959,30 @@ HTMLEditor::SetFinalSize(int32_t aX,
// triggering an immediate reflow; otherwise, we have problems
// with asynchronous reflow
if (setWidth) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::width,
width);
}
if (setHeight) {
mCSSEditUtils->SetCSSPropertyPixels(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->SetCSSPropertyPixels(*mResizedObject, *nsGkAtoms::height,
height);
}
if (setWidth) {
nsAutoString w;
w.AppendInt(width);
SetAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), widthStr, w);
SetAttribute(mResizedObject, nsGkAtoms::width, w);
}
if (setHeight) {
nsAutoString h;
h.AppendInt(height);
SetAttribute(static_cast<nsIDOMElement*>(GetAsDOMNode(mResizedObject)), heightStr, h);
SetAttribute(mResizedObject, nsGkAtoms::height, h);
}
if (setWidth) {
mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::width,
mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::width,
EmptyString());
}
if (setHeight) {
mCSSEditUtils->RemoveCSSProperty(*resizedObject, *nsGkAtoms::height,
mCSSEditUtils->RemoveCSSProperty(*mResizedObject, *nsGkAtoms::height,
EmptyString());
}
}
+14 -16
View File
@@ -429,7 +429,7 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
mCSSEditUtils->IsCSSEditableProperty(&aNode, &aProperty,
aAttribute)) ||
// bgcolor is always done using CSS
aAttribute->EqualsLiteral("bgcolor");
attrAtom == nsGkAtoms::bgcolor;
if (useCSS) {
nsCOMPtr<dom::Element> tmp;
@@ -444,12 +444,9 @@ HTMLEditor::SetInlinePropertyOnNodeImpl(nsIContent& aNode,
}
// Add the CSS styles corresponding to the HTML style request
int32_t count;
nsresult rv =
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp->AsDOMNode(),
&aProperty, aAttribute,
&aValue, &count, false);
NS_ENSURE_SUCCESS(rv, rv);
mCSSEditUtils->SetCSSEquivalentToHTMLStyle(tmp,
&aProperty, attrAtom,
&aValue, false);
return NS_OK;
}
@@ -574,8 +571,9 @@ HTMLEditor::SplitStyleAbovePoint(nsCOMPtr<nsINode>* aNode,
// in this implementation for the node; let's check if it carries those
// CSS styles
nsAutoString firstValue;
mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(GetAsDOMNode(node),
aProperty, aAttribute, isSet, firstValue, CSSEditUtils::eSpecified);
isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(
node, aProperty, aAttribute, firstValue,
CSSEditUtils::eSpecified);
}
if (// node is the correct inline prop
(aProperty && node->IsHTMLElement(aProperty)) ||
@@ -744,8 +742,6 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// if we weren't passed an attribute, then we want to
// remove any matching inlinestyles entirely
if (!aAttribute || aAttribute->IsEmpty()) {
NS_NAMED_LITERAL_STRING(styleAttr, "style");
NS_NAMED_LITERAL_STRING(classAttr, "class");
bool hasStyleAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::style);
bool hasClassAttr = aNode.HasAttr(kNameSpaceID_None, nsGkAtoms::_class);
@@ -754,14 +750,14 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// just remove the element... We need to create above the element
// a span that will carry those styles or class, then we can delete
// the node.
nsCOMPtr<Element> spanNode =
RefPtr<Element> spanNode =
InsertContainerAbove(&aNode, nsGkAtoms::span);
NS_ENSURE_STATE(spanNode);
nsresult rv =
CloneAttribute(styleAttr, spanNode->AsDOMNode(), aNode.AsDOMNode());
CloneAttribute(nsGkAtoms::style, spanNode, aNode.AsElement());
NS_ENSURE_SUCCESS(rv, rv);
rv =
CloneAttribute(classAttr, spanNode->AsDOMNode(), aNode.AsDOMNode());
CloneAttribute(nsGkAtoms::_class, spanNode, aNode.AsElement());
NS_ENSURE_SUCCESS(rv, rv);
}
nsresult rv = RemoveContainer(&aNode);
@@ -794,15 +790,17 @@ HTMLEditor::RemoveStyleInside(nsIContent& aNode,
// the HTML style defined by aProperty/aAttribute has a CSS equivalence in
// this implementation for the node aNode; let's check if it carries those
// css styles
nsCOMPtr<nsIAtom> attribute =
aAttribute ? NS_Atomize(*aAttribute) : nullptr;
nsAutoString propertyValue;
bool isSet = mCSSEditUtils->IsCSSEquivalentToHTMLInlineStyleSet(&aNode,
aProperty, aAttribute, propertyValue, CSSEditUtils::eSpecified);
aProperty, attribute, propertyValue, CSSEditUtils::eSpecified);
if (isSet && aNode.IsElement()) {
// yes, tmp has the corresponding css declarations in its style attribute
// let's remove them
mCSSEditUtils->RemoveCSSEquivalentToHTMLStyle(aNode.AsElement(),
aProperty,
aAttribute,
attribute,
&propertyValue,
false);
// remove the node if it is a span or font, if its style attribute is
+16 -22
View File
@@ -25,7 +25,6 @@
#include "nsError.h"
#include "nsGkAtoms.h"
#include "nsIContent.h"
#include "nsIDOMCharacterData.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMNode.h"
@@ -482,26 +481,24 @@ TextEditRules::CollapseSelectionToTrailingBRIfNeeded(Selection* aSelection)
return NS_OK;
}
static inline already_AddRefed<nsIDOMNode>
GetTextNode(Selection* selection,
EditorBase* editor)
static inline already_AddRefed<nsINode>
GetTextNode(Selection* selection)
{
int32_t selOffset;
nsCOMPtr<nsIDOMNode> selNode;
nsCOMPtr<nsINode> selNode;
nsresult rv =
editor->GetStartNodeAndOffset(selection,
getter_AddRefs(selNode), &selOffset);
EditorBase::GetStartNodeAndOffset(selection,
getter_AddRefs(selNode), &selOffset);
NS_ENSURE_SUCCESS(rv, nullptr);
if (!editor->IsTextNode(selNode)) {
// Get an nsINode from the nsIDOMNode
nsCOMPtr<nsINode> node = do_QueryInterface(selNode);
// if node is null, return it to indicate there's no text
NS_ENSURE_TRUE(node, nullptr);
if (!EditorBase::IsTextNode(selNode)) {
// This should be the root node, walk the tree looking for text nodes
RefPtr<NodeIterator> iter =
new NodeIterator(node, nsIDOMNodeFilter::SHOW_TEXT, NodeFilterHolder());
while (!editor->IsTextNode(selNode)) {
if (NS_FAILED(iter->NextNode(getter_AddRefs(selNode))) || !selNode) {
new NodeIterator(selNode, nsIDOMNodeFilter::SHOW_TEXT,
NodeFilterHolder());
while (!EditorBase::IsTextNode(selNode)) {
IgnoredErrorResult rv;
selNode = iter->NextNode(rv);
if (!selNode) {
return nullptr;
}
}
@@ -1385,13 +1382,10 @@ TextEditRules::HideLastPWInput()
nsContentUtils::GetSelectionInTextControl(selection, mTextEditor->GetRoot(),
start, end);
nsCOMPtr<nsIDOMNode> selNode = GetTextNode(selection, mTextEditor);
nsCOMPtr<nsINode> selNode = GetTextNode(selection);
NS_ENSURE_TRUE(selNode, NS_OK);
nsCOMPtr<nsIDOMCharacterData> nodeAsText(do_QueryInterface(selNode));
NS_ENSURE_TRUE(nodeAsText, NS_OK);
nodeAsText->ReplaceData(mLastStart, mLastLength, hiddenText);
selNode->GetAsText()->ReplaceData(mLastStart, mLastLength, hiddenText);
selection->Collapse(selNode, start);
if (start != end) {
selection->Extend(selNode, end);
@@ -1431,9 +1425,9 @@ TextEditRules::CreateMozBR(nsIDOMNode* inParent,
NS_ENSURE_SUCCESS(rv, rv);
// give it special moz attr
nsCOMPtr<nsIDOMElement> brElem = do_QueryInterface(brNode);
nsCOMPtr<Element> brElem = do_QueryInterface(brNode);
if (brElem) {
rv = mTextEditor->SetAttribute(brElem, NS_LITERAL_STRING("type"),
rv = mTextEditor->SetAttribute(brElem, nsGkAtoms::type,
NS_LITERAL_STRING("_moz"));
NS_ENSURE_SUCCESS(rv, rv);
}
+6 -6
View File
@@ -310,9 +310,9 @@ TextEditor::UpdateMetaCharset(nsIDOMDocument* aDocument,
}
// set attribute to <original prefix> charset=text/html
nsCOMPtr<nsIDOMElement> metaElement = do_QueryInterface(metaNode);
RefPtr<Element> metaElement = metaNode->AsElement();
MOZ_ASSERT(metaElement);
rv = EditorBase::SetAttribute(metaElement, NS_LITERAL_STRING("content"),
rv = EditorBase::SetAttribute(metaElement, nsGkAtoms::content,
Substring(originalStart, start) +
charsetEquals +
NS_ConvertASCIItoUTF16(aCharacterSet));
@@ -1621,8 +1621,8 @@ TextEditor::GetDOMEventTarget()
nsresult
TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
TextEditor::SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction)
{
@@ -1630,8 +1630,8 @@ TextEditor::SetAttributeOrEquivalent(nsIDOMElement* aElement,
}
nsresult
TextEditor::RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
TextEditor::RemoveAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction)
{
return EditorBase::RemoveAttribute(aElement, aAttribute);
+11 -8
View File
@@ -63,14 +63,17 @@ public:
// nsIEditorMailSupport overrides
NS_DECL_NSIEDITORMAILSUPPORT
// Overrides of EditorBase interface methods
NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement* aElement,
const nsAString& aAttribute,
bool aSuppressTransaction) override;
// Overrides of EditorBase
virtual nsresult RemoveAttributeOrEquivalent(
Element* aElement,
nsIAtom* aAttribute,
bool aSuppressTransaction) override;
virtual nsresult SetAttributeOrEquivalent(Element* aElement,
nsIAtom* aAttribute,
const nsAString& aValue,
bool aSuppressTransaction) override;
using EditorBase::RemoveAttributeOrEquivalent;
using EditorBase::SetAttributeOrEquivalent;
NS_IMETHOD Init(nsIDOMDocument* aDoc, nsIContent* aRoot,
nsISelectionController* aSelCon, uint32_t aFlags,
+2 -2
View File
@@ -242,13 +242,13 @@ ClippedImage::GetIntrinsicSize(nsSize* aSize)
}
NS_IMETHODIMP
ClippedImage::GetIntrinsicRatio(nsSize* aRatio)
ClippedImage::GetIntrinsicRatio(AspectRatio* aRatio)
{
if (!ShouldClip()) {
return InnerImage()->GetIntrinsicRatio(aRatio);
}
*aRatio = nsSize(mClip.width, mClip.height);
*aRatio = AspectRatio::FromSize(mClip.width, mClip.height);
return NS_OK;
}
+1 -1
View File
@@ -35,7 +35,7 @@ public:
NS_IMETHOD GetWidth(int32_t* aWidth) override;
NS_IMETHOD GetHeight(int32_t* aHeight) override;
NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD GetIntrinsicRatio(AspectRatio* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
+3 -3
View File
@@ -136,10 +136,10 @@ DynamicImage::GetIntrinsicSize(nsSize* aSize)
}
NS_IMETHODIMP
DynamicImage::GetIntrinsicRatio(nsSize* aSize)
DynamicImage::GetIntrinsicRatio(AspectRatio* aRatio)
{
IntSize intSize(mDrawable->Size());
*aSize = nsSize(intSize.width, intSize.height);
auto size = mDrawable->Size();
*aRatio = AspectRatio::FromSize(size);
return NS_OK;
}
+2 -2
View File
@@ -146,9 +146,9 @@ ImageWrapper::GetIntrinsicSize(nsSize* aSize)
}
NS_IMETHODIMP
ImageWrapper::GetIntrinsicRatio(nsSize* aSize)
ImageWrapper::GetIntrinsicRatio(AspectRatio* aRatio)
{
return mInnerImage->GetIntrinsicRatio(aSize);
return mInnerImage->GetIntrinsicRatio(aRatio);
}
NS_IMETHODIMP_(Orientation)
+2 -2
View File
@@ -59,12 +59,12 @@ OrientedImage::GetIntrinsicSize(nsSize* aSize)
}
NS_IMETHODIMP
OrientedImage::GetIntrinsicRatio(nsSize* aRatio)
OrientedImage::GetIntrinsicRatio(AspectRatio* aRatio)
{
nsresult rv = InnerImage()->GetIntrinsicRatio(aRatio);
if (mOrientation.SwapsWidthAndHeight()) {
swap(aRatio->width, aRatio->height);
*aRatio = aRatio->Inverted();
}
return rv;
+1 -1
View File
@@ -31,7 +31,7 @@ public:
NS_IMETHOD GetWidth(int32_t* aWidth) override;
NS_IMETHOD GetHeight(int32_t* aHeight) override;
NS_IMETHOD GetIntrinsicSize(nsSize* aSize) override;
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) override;
NS_IMETHOD GetIntrinsicRatio(AspectRatio* aRatio) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
GetFrame(uint32_t aWhichFrame, uint32_t aFlags) override;
NS_IMETHOD_(already_AddRefed<SourceSurface>)
+3 -2
View File
@@ -240,13 +240,14 @@ RasterImage::GetIntrinsicSize(nsSize* aSize)
//******************************************************************************
NS_IMETHODIMP
RasterImage::GetIntrinsicRatio(nsSize* aRatio)
RasterImage::GetIntrinsicRatio(AspectRatio* aRatio)
{
if (mError) {
return NS_ERROR_FAILURE;
}
*aRatio = nsSize(mSize.width, mSize.height);
*aRatio = AspectRatio::FromSize(mSize);
return NS_OK;
}
+1 -1
View File
@@ -628,7 +628,7 @@ VectorImage::GetIntrinsicSize(nsSize* aSize)
//******************************************************************************
NS_IMETHODIMP
VectorImage::GetIntrinsicRatio(nsSize* aRatio)
VectorImage::GetIntrinsicRatio(AspectRatio* aRatio)
{
if (mError || !mIsFullyLoaded) {
return NS_ERROR_FAILURE;
+3 -1
View File
@@ -12,6 +12,7 @@
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/AspectRatio.h"
#include "mozilla/Maybe.h"
#include "mozilla/RefPtr.h"
#include "nsRect.h"
@@ -55,6 +56,7 @@ native SamplingFilter(mozilla::gfx::SamplingFilter);
native nsIntRectByVal(nsIntRect);
[ref] native nsIntSize(nsIntSize);
native nsSize(nsSize);
native AspectRatio(mozilla::AspectRatio);
[ptr] native nsIFrame(nsIFrame);
native TempRefImageContainer(already_AddRefed<mozilla::layers::ImageContainer>);
[ref] native ImageRegion(mozilla::image::ImageRegion);
@@ -101,7 +103,7 @@ interface imgIContainer : nsISupports
* The (dimensionless) intrinsic ratio of this image. In the case of any
* error, an exception will be thrown.
*/
[noscript] readonly attribute nsSize intrinsicRatio;
[noscript] readonly attribute AspectRatio intrinsicRatio;
/**
* Given a size at which this image will be displayed, and the drawing
+1 -1
View File
@@ -779,7 +779,7 @@ struct JSClass {
// application.
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5
#define JSCLASS_GLOBAL_SLOT_COUNT \
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 46)
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 45)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \
+37
View File
@@ -51,6 +51,7 @@ const size_t ChunkMarkBitmapBits = 129024;
const size_t ChunkRuntimeOffset = ChunkSize - sizeof(void*);
const size_t ChunkTrailerSize = 2 * sizeof(uintptr_t) + sizeof(uint64_t);
const size_t ChunkLocationOffset = ChunkSize - ChunkTrailerSize;
const size_t ChunkStoreBufferOffset = ChunkSize - ChunkTrailerSize + sizeof(uint64_t);
const size_t ArenaZoneOffset = sizeof(size_t);
const size_t ArenaHeaderSize = sizeof(size_t) + 2 * sizeof(uintptr_t) +
sizeof(size_t) + sizeof(uintptr_t);
@@ -326,6 +327,20 @@ CellIsMarkedGray(const Cell* cell)
extern JS_PUBLIC_API(bool)
CellIsMarkedGrayIfKnown(const Cell* cell);
MOZ_ALWAYS_INLINE ChunkLocation GetCellLocation(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkLocationOffset;
return *reinterpret_cast<ChunkLocation*>(addr);
}
MOZ_ALWAYS_INLINE bool NurseryCellHasStoreBuffer(const void* cell) {
uintptr_t addr = uintptr_t(cell);
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkStoreBufferOffset;
return *reinterpret_cast<void**>(addr) != nullptr;
}
} /* namespace detail */
MOZ_ALWAYS_INLINE bool
@@ -341,6 +356,28 @@ IsInsideNursery(const js::gc::Cell* cell)
return location == ChunkLocation::Nursery;
}
MOZ_ALWAYS_INLINE bool IsCellPointerValid(const void* cell) {
auto addr = uintptr_t(cell);
if (addr < ChunkSize || addr % CellSize != 0) {
return false;
}
auto location = detail::GetCellLocation(cell);
if (location == ChunkLocation::TenuredHeap) {
return !!detail::GetGCThingZone(addr);
}
if (location == ChunkLocation::Nursery) {
return detail::NurseryCellHasStoreBuffer(cell);
}
return false;
}
MOZ_ALWAYS_INLINE bool IsCellPointerValidOrNull(const void* cell) {
if (!cell) {
return true;
}
return IsCellPointerValid(cell);
}
} /* namespace gc */
} /* namespace js */
+146 -154
View File
@@ -67,10 +67,16 @@ function ModuleGetExportedNames(exportStarSet = [])
function ModuleSetStatus(module, newStatus)
{
assert(newStatus >= MODULE_STATUS_ERRORED && newStatus <= MODULE_STATUS_EVALUATED,
assert(newStatus >= MODULE_STATUS_UNINSTANTIATED &&
newStatus <= MODULE_STATUS_EVALUATED_ERROR,
"Bad new module status in ModuleSetStatus");
if (newStatus !== MODULE_STATUS_ERRORED)
assert(newStatus > module.status, "New module status inconsistent with current status");
// Note that under OOM conditions we can fail the module instantiation
// process even after modules have been marked as instantiated.
assert((module.status <= MODULE_STATUS_INSTANTIATED &&
newStatus === MODULE_STATUS_UNINSTANTIATED) ||
newStatus > module.status,
"New module status inconsistent with current status");
UnsafeSetReservedSlot(module, MODULE_OBJECT_STATUS_SLOT, newStatus);
}
@@ -80,20 +86,15 @@ function ModuleSetStatus(module, newStatus)
// Returns an object describing the location of the resolved export or
// indicating a failure.
//
// On success this returns: { resolved: true, module, bindingName }
// On success this returns a resolved binding record: { module, bindingName }
//
// There are three failure cases:
// There are two failure cases:
//
// - The resolution failure can be blamed on a particular module.
// Returns: { resolved: false, module, ambiguous: false }
// - If no definition was found or the request is found to be circular, *null*
// is returned.
//
// - No culprit can be determined and the resolution failure was due to star
// export ambiguity.
// Returns: { resolved: false, module: null, ambiguous: true }
//
// - No culprit can be determined and the resolution failure was not due to
// star export ambiguity.
// Returns: { resolved: false, module: null, ambiguous: false }
// - If the request is found to be ambiguous, the string `"ambiguous"` is
// returned.
//
function ModuleResolveExport(exportName, resolveSet = [])
{
@@ -106,53 +107,47 @@ function ModuleResolveExport(exportName, resolveSet = [])
let module = this;
// Step 2
assert(module.status !== MODULE_STATUS_ERRORED, "Bad module status in ResolveExport");
// Step 3
for (let i = 0; i < resolveSet.length; i++) {
let r = resolveSet[i];
if (r.module === module && r.exportName === exportName) {
// This is a circular import request.
return {resolved: false, module: null, ambiguous: false};
return null;
}
}
// Step 4
// Step 3
_DefineDataProperty(resolveSet, resolveSet.length, {module: module, exportName: exportName});
// Step 5
// Step 4
let localExportEntries = module.localExportEntries;
for (let i = 0; i < localExportEntries.length; i++) {
let e = localExportEntries[i];
if (exportName === e.exportName)
return {resolved: true, module, bindingName: e.localName};
return {module, bindingName: e.localName};
}
// Step 6
// Step 5
let indirectExportEntries = module.indirectExportEntries;
for (let i = 0; i < indirectExportEntries.length; i++) {
let e = indirectExportEntries[i];
if (exportName === e.exportName) {
let importedModule = CallModuleResolveHook(module, e.moduleRequest,
MODULE_STATUS_UNINSTANTIATED);
let resolution = callFunction(importedModule.resolveExport, importedModule, e.importName,
resolveSet);
if (!resolution.resolved && !resolution.module)
resolution.module = module;
return resolution;
return callFunction(importedModule.resolveExport, importedModule, e.importName,
resolveSet);
}
}
// Step 7
// Step 6
if (exportName === "default") {
// A default export cannot be provided by an export *.
return {resolved: false, module: null, ambiguous: false};
return null;
}
// Step 8
// Step 7
let starResolution = null;
// Step 9
// Step 8
let starExportEntries = module.starExportEntries;
for (let i = 0; i < starExportEntries.length; i++) {
let e = starExportEntries[i];
@@ -160,27 +155,31 @@ function ModuleResolveExport(exportName, resolveSet = [])
MODULE_STATUS_UNINSTANTIATED);
let resolution = callFunction(importedModule.resolveExport, importedModule, exportName,
resolveSet);
if (!resolution.resolved && (resolution.module || resolution.ambiguous))
if (resolution === "ambiguous")
return resolution;
if (resolution.resolved) {
if (resolution !== null) {
if (starResolution === null) {
starResolution = resolution;
} else {
if (resolution.module !== starResolution.module ||
resolution.bindingName !== starResolution.bindingName)
{
return {resolved: false, module: null, ambiguous: true};
return "ambiguous";
}
}
}
}
// Step 10
if (starResolution !== null)
return starResolution;
// Step 9
return starResolution;
}
return {resolved: false, module: null, ambiguous: false};
function IsResolvedBinding(resolution)
{
assert(resolution === "ambiguous" || typeof resolution === "object",
"Bad module resolution result");
return typeof resolution === "object" && resolution !== null;
}
// 15.2.1.18 GetModuleNamespace(module)
@@ -189,12 +188,12 @@ function GetModuleNamespace(module)
// Step 1
assert(IsModule(module), "GetModuleNamespace called with non-module");
// Step 2
// Steps 2-3
assert(module.status !== MODULE_STATUS_UNINSTANTIATED &&
module.status !== MODULE_STATUS_ERRORED,
module.status !== MODULE_STATUS_EVALUATED_ERROR,
"Bad module status in GetModuleNamespace");
// Step 3
// Step 4
let namespace = module.namespace;
if (typeof namespace === "undefined") {
@@ -203,7 +202,7 @@ function GetModuleNamespace(module)
for (let i = 0; i < exportedNames.length; i++) {
let name = exportedNames[i];
let resolution = callFunction(module.resolveExport, module, name);
if (resolution.resolved)
if (IsResolvedBinding(resolution))
_DefineDataProperty(unambiguousNames, unambiguousNames.length, name);
}
namespace = ModuleNamespaceCreate(module, unambiguousNames);
@@ -225,7 +224,7 @@ function ModuleNamespaceCreate(module, exports)
for (let i = 0; i < exports.length; i++) {
let name = exports[i];
let binding = callFunction(module.resolveExport, module, name);
assert(binding.resolved, "Failed to resolve binding");
assert(IsResolvedBinding(binding), "Failed to resolve binding");
AddModuleNamespaceBinding(ns, name, binding.module, binding.bindingName);
}
@@ -236,31 +235,16 @@ function GetModuleEnvironment(module)
{
assert(IsModule(module), "Non-module passed to GetModuleEnvironment");
// Check for a previous failed attempt to instantiate this module. This can
// only happen due to a bug in the module loader.
if (module.status === MODULE_STATUS_ERRORED)
ThrowInternalError(JSMSG_MODULE_INSTANTIATE_FAILED, module.status);
assert(module.status >= MODULE_STATUS_INSTANTIATING,
"Attempt to access module environement before instantation");
let env = UnsafeGetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT);
assert(env === undefined || IsModuleEnvironment(env),
assert(IsModuleEnvironment(env),
"Module environment slot contains unexpected value");
return env;
}
function RecordModuleError(module, error)
{
// Set the module's status to 'errored' to indicate a failed module
// instantiation and record the exception. The environment slot is also
// reset to 'undefined'.
assert(IsObject(module) && IsModule(module), "Non-module passed to RecordModuleError");
ModuleSetStatus(module, MODULE_STATUS_ERRORED);
UnsafeSetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT, error);
UnsafeSetReservedSlot(module, MODULE_OBJECT_ENVIRONMENT_SLOT, undefined);
}
function CountArrayValues(array, value)
{
let count = 0;
@@ -280,6 +264,16 @@ function ArrayContains(array, value)
return false;
}
function HandleModuleInstantiationFailure(module)
{
// Reset the module to the "uninstantiated" state. Don't reset the
// environment slot as the environment object will be required by any
// possible future instantiation attempt.
ModuleSetStatus(module, MODULE_STATUS_UNINSTANTIATED);
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, undefined);
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, undefined);
}
// 15.2.1.16.4 ModuleInstantiate()
function ModuleInstantiate()
{
@@ -301,38 +295,30 @@ function ModuleInstantiate()
// Steps 4-5
try {
InnerModuleDeclarationInstantiation(module, stack, 0);
InnerModuleInstantiation(module, stack, 0);
} catch (error) {
for (let i = 0; i < stack.length; i++) {
let m = stack[i];
assert(m.status === MODULE_STATUS_INSTANTIATING ||
m.status === MODULE_STATUS_ERRORED,
"Bad module status after failed instantiation");
RecordModuleError(m, error);
assert(m.status === MODULE_STATUS_INSTANTIATING,
"Expected instantiating status during failed instantiation");
HandleModuleInstantiationFailure(m);
}
if (stack.length === 0 &&
typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined")
{
// This can happen due to OOM when appending to the stack.
assert(error === "out of memory",
"Stack must contain module unless we hit OOM");
RecordModuleError(module, error);
}
// Handle OOM when appending to the stack or over-recursion errors.
if (stack.length === 0)
HandleModuleInstantiationFailure(module);
assert(module.status === MODULE_STATUS_ERRORED,
"Bad module status after failed instantiation");
assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error),
"Module has different error set after failed instantiation");
assert(module.status === MODULE_STATUS_UNINSTANTIATED,
"Expected uninstantiated status after failed instantiation");
throw error;
}
// Step 6
assert(module.status == MODULE_STATUS_INSTANTIATED ||
module.status == MODULE_STATUS_EVALUATED,
assert(module.status === MODULE_STATUS_INSTANTIATED ||
module.status === MODULE_STATUS_EVALUATED ||
module.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad module status after successful instantiation");
// Step 7
@@ -344,8 +330,8 @@ function ModuleInstantiate()
}
_SetCanonicalName(ModuleInstantiate, "ModuleInstantiate");
// 15.2.1.16.4.1 InnerModuleDeclarationInstantiation(module, stack, index)
function InnerModuleDeclarationInstantiation(module, stack, index)
// 15.2.1.16.4.1 InnerModuleInstantiation(module, stack, index)
function InnerModuleInstantiation(module, stack, index)
{
// Step 1
// TODO: Support module records other than source text module records.
@@ -353,42 +339,40 @@ function InnerModuleDeclarationInstantiation(module, stack, index)
// Step 2
if (module.status === MODULE_STATUS_INSTANTIATING ||
module.status === MODULE_STATUS_INSTANTIATED ||
module.status === MODULE_STATUS_EVALUATED)
module.status === MODULE_STATUS_EVALUATED ||
module.status === MODULE_STATUS_EVALUATED_ERROR)
{
return index;
}
// Step 3
if (module.status === MODULE_STATUS_ERRORED)
throw module.error;
// Step 4
assert(module.status === MODULE_STATUS_UNINSTANTIATED,
"Bad module status in ModuleDeclarationInstantiation");
// Steps 5
// Step 4
ModuleSetStatus(module, MODULE_STATUS_INSTANTIATING);
// Step 6-8
// Steps 5-7
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_INDEX_SLOT, index);
UnsafeSetReservedSlot(module, MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT, index);
index++;
// Step 9
// Step 8
_DefineDataProperty(stack, stack.length, module);
// Step 10
// Step 9
let requestedModules = module.requestedModules;
for (let i = 0; i < requestedModules.length; i++) {
let required = requestedModules[i];
let requiredModule = CallModuleResolveHook(module, required, MODULE_STATUS_ERRORED);
let requiredModule = CallModuleResolveHook(module, required, MODULE_STATUS_UNINSTANTIATED);
index = InnerModuleDeclarationInstantiation(requiredModule, stack, index);
index = InnerModuleInstantiation(requiredModule, stack, index);
assert(requiredModule.status === MODULE_STATUS_INSTANTIATING ||
requiredModule.status === MODULE_STATUS_INSTANTIATED ||
requiredModule.status === MODULE_STATUS_EVALUATED,
"Bad required module status after InnerModuleDeclarationInstantiation");
requiredModule.status === MODULE_STATUS_EVALUATED ||
requiredModule.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad required module status after InnerModuleInstantiation");
assert((requiredModule.status === MODULE_STATUS_INSTANTIATING) ===
ArrayContains(stack, requiredModule),
@@ -404,16 +388,16 @@ function InnerModuleDeclarationInstantiation(module, stack, index)
}
}
// Step 11
// Step 10
ModuleDeclarationEnvironmentSetup(module);
// Steps 12-13
// Steps 11-12
assert(CountArrayValues(stack, module) === 1,
"Current module should appear exactly once in the stack");
assert(module.dfsAncestorIndex <= module.dfsIndex,
"Bad DFS ancestor index");
// Step 14
// Step 13
if (module.dfsAncestorIndex === module.dfsIndex) {
let requiredModule;
do {
@@ -434,16 +418,14 @@ function ModuleDeclarationEnvironmentSetup(module)
for (let i = 0; i < indirectExportEntries.length; i++) {
let e = indirectExportEntries[i];
let resolution = callFunction(module.resolveExport, module, e.exportName);
assert(resolution.resolved || resolution.module,
"Unexpected failure to resolve export in ModuleDeclarationEnvironmentSetup");
if (!resolution.resolved) {
return ResolutionError(resolution, "indirectExport", e.exportName,
e.lineNumber, e.columnNumber)
if (!IsResolvedBinding(resolution)) {
ThrowResolutionError(module, resolution, "indirectExport", e.exportName,
e.lineNumber, e.columnNumber);
}
}
// Steps 5-6
CreateModuleEnvironment(module);
// Note that we have already created the environment by this point.
let env = GetModuleEnvironment(module);
// Step 8
@@ -458,12 +440,9 @@ function ModuleDeclarationEnvironmentSetup(module)
} else {
let resolution = callFunction(importedModule.resolveExport, importedModule,
imp.importName);
if (!resolution.resolved && !resolution.module)
resolution.module = module;
if (!resolution.resolved) {
return ResolutionError(resolution, "import", imp.importName,
imp.lineNumber, imp.columnNumber);
if (!IsResolvedBinding(resolution)) {
ThrowResolutionError(module, resolution, "import", imp.importName,
imp.lineNumber, imp.columnNumber);
}
CreateImportBinding(env, imp.localName, resolution.module, resolution.bindingName);
@@ -473,38 +452,58 @@ function ModuleDeclarationEnvironmentSetup(module)
InstantiateModuleFunctionDeclarations(module);
}
// 15.2.1.16.4.3 ResolutionError(module)
function ResolutionError(resolution, kind, name, line, column)
function ThrowResolutionError(module, resolution, kind, name, line, column)
{
let module = resolution.module;
assert(module !== null,
"Null module passed to ResolutionError");
assert(module.status === MODULE_STATUS_UNINSTANTIATED ||
module.status === MODULE_STATUS_INSTANTIATING,
"Unexpected module status in ResolutionError");
assert(module.status === MODULE_STATUS_INSTANTIATING,
"Unexpected module status in ThrowResolutionError");
assert(kind === "import" || kind === "indirectExport",
"Unexpected kind in ResolutionError");
"Unexpected kind in ThrowResolutionError");
assert(line > 0,
"Line number should be present for all imports and indirect exports");
let ambiguous = resolution === "ambiguous";
let errorNumber;
if (kind === "import") {
errorNumber = resolution.ambiguous ? JSMSG_AMBIGUOUS_IMPORT
: JSMSG_MISSING_IMPORT;
} else {
errorNumber = resolution.ambiguous ? JSMSG_AMBIGUOUS_INDIRECT_EXPORT
: JSMSG_MISSING_INDIRECT_EXPORT;
}
if (kind === "import")
errorNumber = ambiguous ? JSMSG_AMBIGUOUS_IMPORT : JSMSG_MISSING_IMPORT;
else
errorNumber = ambiguous ? JSMSG_AMBIGUOUS_INDIRECT_EXPORT : JSMSG_MISSING_INDIRECT_EXPORT;
let message = GetErrorMessage(errorNumber) + ": " + name;
let error = CreateModuleSyntaxError(module, line, column, message);
RecordModuleError(module, error);
throw error;
}
function GetModuleEvaluationError(module)
{
assert(IsObject(module) && IsModule(module),
"Non-module passed to GetModuleEvaluationError");
assert(module.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad module status in GetModuleEvaluationError");
return UnsafeGetReservedSlot(module, MODULE_OBJECT_EVALUATION_ERROR_SLOT);
}
function RecordModuleEvaluationError(module, error)
{
// Set the module's EvaluationError slot to indicate a failed module
// evaluation.
assert(IsObject(module) && IsModule(module),
"Non-module passed to RecordModuleEvaluationError");
if (module.status === MODULE_STATUS_EVALUATED_ERROR) {
// It would be nice to assert that |error| is the same as the one we
// previously recorded, but that's not always true in the case of out of
// memory and over-recursion errors.
return;
}
ModuleSetStatus(module, MODULE_STATUS_EVALUATED_ERROR);
UnsafeSetReservedSlot(module, MODULE_OBJECT_EVALUATION_ERROR_SLOT, error);
}
// 15.2.1.16.5 ModuleEvaluate()
function ModuleEvaluate()
{
@@ -515,9 +514,9 @@ function ModuleEvaluate()
let module = this;
// Step 2
if (module.status !== MODULE_STATUS_ERRORED &&
module.status !== MODULE_STATUS_INSTANTIATED &&
module.status !== MODULE_STATUS_EVALUATED)
if (module.status !== MODULE_STATUS_INSTANTIATED &&
module.status !== MODULE_STATUS_EVALUATED &&
module.status !== MODULE_STATUS_EVALUATED_ERROR)
{
ThrowInternalError(JSMSG_BAD_MODULE_STATUS);
}
@@ -535,27 +534,20 @@ function ModuleEvaluate()
assert(m.status === MODULE_STATUS_EVALUATING,
"Bad module status after failed evaluation");
RecordModuleError(m, error);
RecordModuleEvaluationError(m, error);
}
if (stack.length === 0 &&
typeof(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT)) === "undefined")
{
// This can happen due to OOM when appending to the stack.
assert(error === "out of memory",
"Stack must contain module unless we hit OOM");
RecordModuleError(module, error);
}
// Handle OOM when appending to the stack or over-recursion errors.
if (stack.length === 0)
RecordModuleEvaluationError(module, error);
assert(module.status === MODULE_STATUS_ERRORED,
assert(module.status === MODULE_STATUS_EVALUATED_ERROR,
"Bad module status after failed evaluation");
assert(SameValue(UnsafeGetReservedSlot(module, MODULE_OBJECT_ERROR_SLOT), error),
"Module has different error set after failed evaluation");
throw error;
}
assert(module.status == MODULE_STATUS_EVALUATED,
assert(module.status === MODULE_STATUS_EVALUATED,
"Bad module status after successful evaluation");
assert(stack.length === 0,
"Stack should be empty after successful evaluation");
@@ -571,19 +563,19 @@ function InnerModuleEvaluation(module, stack, index)
// TODO: Support module records other than source text module records.
// Step 2
if (module.status === MODULE_STATUS_EVALUATING ||
module.status === MODULE_STATUS_EVALUATED)
{
if (module.status === MODULE_STATUS_EVALUATED_ERROR)
throw GetModuleEvaluationError(module);
if (module.status === MODULE_STATUS_EVALUATED)
return index;
}
// Step 3
if (module.status === MODULE_STATUS_ERRORED)
throw module.error;
if (module.status === MODULE_STATUS_EVALUATING)
return index;
// Step 4
assert(module.status === MODULE_STATUS_INSTANTIATED,
"Bad module status in ModuleEvaluation");
"Bad module status in InnerModuleEvaluation");
// Step 5
ModuleSetStatus(module, MODULE_STATUS_EVALUATING);
@@ -605,8 +597,8 @@ function InnerModuleEvaluation(module, stack, index)
index = InnerModuleEvaluation(requiredModule, stack, index);
assert(requiredModule.status == MODULE_STATUS_EVALUATING ||
requiredModule.status == MODULE_STATUS_EVALUATED,
assert(requiredModule.status === MODULE_STATUS_EVALUATING ||
requiredModule.status === MODULE_STATUS_EVALUATED,
"Bad module status after InnerModuleEvaluation");
assert((requiredModule.status === MODULE_STATUS_EVALUATING) ===
+67 -54
View File
@@ -18,10 +18,10 @@
using namespace js;
using namespace js::frontend;
static_assert(MODULE_STATUS_ERRORED < MODULE_STATUS_UNINSTANTIATED &&
MODULE_STATUS_UNINSTANTIATED < MODULE_STATUS_INSTANTIATING &&
static_assert(MODULE_STATUS_UNINSTANTIATED < MODULE_STATUS_INSTANTIATING &&
MODULE_STATUS_INSTANTIATING < MODULE_STATUS_INSTANTIATED &&
MODULE_STATUS_INSTANTIATED < MODULE_STATUS_EVALUATED,
MODULE_STATUS_INSTANTIATED < MODULE_STATUS_EVALUATED &&
MODULE_STATUS_EVALUATED < MODULE_STATUS_EVALUATED_ERROR,
"Module statuses are ordered incorrectly");
template<typename T, Value ValueGetter(const T* obj)>
@@ -248,21 +248,13 @@ IndirectBindingMap::Binding::Binding(ModuleEnvironmentObject* environment, Shape
: environment(environment), shape(shape)
{}
IndirectBindingMap::IndirectBindingMap(Zone* zone)
: map_(ZoneAllocPolicy(zone))
{
}
bool
IndirectBindingMap::init()
{
return map_.init();
}
void
IndirectBindingMap::trace(JSTracer* trc)
{
for (Map::Enum e(map_); !e.empty(); e.popFront()) {
if (!map_)
return;
for (Map::Enum e(*map_); !e.empty(); e.popFront()) {
Binding& b = e.front().value();
TraceEdge(trc, &b.environment, "module bindings environment");
TraceEdge(trc, &b.shape, "module bindings shape");
@@ -273,12 +265,25 @@ IndirectBindingMap::trace(JSTracer* trc)
}
bool
IndirectBindingMap::putNew(JSContext* cx, HandleId name,
HandleModuleEnvironmentObject environment, HandleId localName)
IndirectBindingMap::put(JSContext* cx, HandleId name,
HandleModuleEnvironmentObject environment, HandleId localName)
{
// This object might have been allocated on the background parsing thread in
// different zone to the final module. Lazily allocate the map so we don't
// have to switch its zone when merging compartments.
if (!map_) {
MOZ_ASSERT(!cx->zone()->usedByExclusiveThread);
map_.emplace(cx->zone());
if (!map_->init()) {
map_.reset();
ReportOutOfMemory(cx);
return false;
}
}
RootedShape shape(cx, environment->lookup(cx, localName));
MOZ_ASSERT(shape);
if (!map_.putNew(name, Binding(environment, shape))) {
if (!map_->put(name, Binding(environment, shape))) {
ReportOutOfMemory(cx);
return false;
}
@@ -289,7 +294,10 @@ IndirectBindingMap::putNew(JSContext* cx, HandleId name,
bool
IndirectBindingMap::lookup(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut) const
{
auto ptr = map_.lookup(name);
if (!map_)
return false;
auto ptr = map_->lookup(name);
if (!ptr)
return false;
@@ -359,7 +367,7 @@ ModuleNamespaceObject::addBinding(JSContext* cx, HandleAtom exportedName,
RootedModuleEnvironmentObject environment(cx, &targetModule->initialEnvironment());
RootedId exportedNameId(cx, AtomToId(exportedName));
RootedId localNameId(cx, AtomToId(localName));
return bindings->putNew(cx, exportedNameId, environment, localNameId);
return bindings->put(cx, exportedNameId, environment, localNameId);
}
const char ModuleNamespaceObject::ProxyHandler::family = 0;
@@ -625,10 +633,9 @@ ModuleObject::create(ExclusiveContext* cx)
RootedModuleObject self(cx, &obj->as<ModuleObject>());
Zone* zone = cx->zone();
IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>(zone);
if (!bindings || !bindings->init()) {
IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>();
if (!bindings) {
ReportOutOfMemory(cx);
js_delete<IndirectBindingMap>(bindings);
return nullptr;
}
@@ -657,14 +664,24 @@ ModuleObject::finalize(js::FreeOp* fop, JSObject* obj)
fop->delete_(funDecls);
}
ModuleEnvironmentObject&
ModuleObject::initialEnvironment() const
{
Value value = getReservedSlot(EnvironmentSlot);
return value.toObject().as<ModuleEnvironmentObject>();
}
ModuleEnvironmentObject*
ModuleObject::environment() const
{
Value value = getReservedSlot(EnvironmentSlot);
if (value.isUndefined())
MOZ_ASSERT(!hadEvaluationError());
// According to the spec the environment record is created during
// instantiation, but we create it earlier than that.
if (status() < MODULE_STATUS_INSTANTIATED)
return nullptr;
return &value.toObject().as<ModuleEnvironmentObject>();
return &initialEnvironment();
}
bool
@@ -723,13 +740,13 @@ void
ModuleObject::init(HandleScript script)
{
initReservedSlot(ScriptSlot, PrivateValue(script));
initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_ERRORED));
initReservedSlot(StatusSlot, Int32Value(MODULE_STATUS_UNINSTANTIATED));
}
void
ModuleObject::setInitialEnvironment(HandleModuleEnvironmentObject initialEnvironment)
{
initReservedSlot(InitialEnvironmentSlot, ObjectValue(*initialEnvironment));
initReservedSlot(EnvironmentSlot, ObjectValue(*initialEnvironment));
}
void
@@ -827,7 +844,8 @@ ModuleObject::script() const
static inline void
AssertValidModuleStatus(ModuleStatus status)
{
MOZ_ASSERT(status >= MODULE_STATUS_ERRORED && status <= MODULE_STATUS_EVALUATED);
MOZ_ASSERT(status >= MODULE_STATUS_UNINSTANTIATED &&
status <= MODULE_STATUS_EVALUATED_ERROR);
}
ModuleStatus
@@ -838,11 +856,17 @@ ModuleObject::status() const
return status;
}
Value
ModuleObject::error() const
bool
ModuleObject::hadEvaluationError() const
{
MOZ_ASSERT(status() == MODULE_STATUS_ERRORED);
return getReservedSlot(ErrorSlot);
return status() == MODULE_STATUS_EVALUATED_ERROR;
}
Value
ModuleObject::evaluationError() const
{
MOZ_ASSERT(hadEvaluationError());
return getReservedSlot(EvaluationErrorSlot);
}
Value
@@ -857,12 +881,6 @@ ModuleObject::setHostDefinedField(const JS::Value& value)
setReservedSlot(HostDefinedSlot, value);
}
ModuleEnvironmentObject&
ModuleObject::initialEnvironment() const
{
return getReservedSlot(InitialEnvironmentSlot).toObject().as<ModuleEnvironmentObject>();
}
Scope*
ModuleObject::enclosingScope() const
{
@@ -888,16 +906,6 @@ ModuleObject::trace(JSTracer* trc, JSObject* obj)
funDecls->trace(trc);
}
void
ModuleObject::createEnvironment()
{
// The environment has already been created, we just neet to set it in the
// right slot.
MOZ_ASSERT(!getReservedSlot(InitialEnvironmentSlot).isUndefined());
MOZ_ASSERT(getReservedSlot(EnvironmentSlot).isUndefined());
setReservedSlot(EnvironmentSlot, getReservedSlot(InitialEnvironmentSlot));
}
bool
ModuleObject::noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, HandleFunction fun)
{
@@ -913,7 +921,10 @@ ModuleObject::noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, Han
/* static */ bool
ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject self)
{
#ifdef DEBUG
MOZ_ASSERT(self->status() == MODULE_STATUS_INSTANTIATING);
MOZ_ASSERT(IsFrozen(cx, self));
#endif
FunctionDeclarationVector* funDecls = self->functionDeclarations();
if (!funDecls) {
@@ -944,7 +955,10 @@ ModuleObject::instantiateFunctionDeclarations(JSContext* cx, HandleModuleObject
/* static */ bool
ModuleObject::execute(JSContext* cx, HandleModuleObject self, MutableHandleValue rval)
{
#ifdef DEBUG
MOZ_ASSERT(self->status() == MODULE_STATUS_EVALUATING);
MOZ_ASSERT(IsFrozen(cx, self));
#endif
RootedScript script(cx, self->script());
RootedModuleEnvironmentObject scope(cx, self->environment());
@@ -967,10 +981,9 @@ ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObje
return nullptr;
Zone* zone = cx->zone();
IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>(zone);
if (!bindings || !bindings->init()) {
IndirectBindingMap* bindings = zone->new_<IndirectBindingMap>();
if (!bindings) {
ReportOutOfMemory(cx);
js_delete<IndirectBindingMap>(bindings);
return nullptr;
}
@@ -1005,7 +1018,7 @@ ModuleObject::Evaluate(JSContext* cx, HandleModuleObject self)
DEFINE_GETTER_FUNCTIONS(ModuleObject, namespace_, NamespaceSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, status, StatusSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, error, ErrorSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, evaluationError, EvaluationErrorSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, requestedModules, RequestedModulesSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, importEntries, ImportEntriesSlot)
DEFINE_GETTER_FUNCTIONS(ModuleObject, localExportEntries, LocalExportEntriesSlot)
@@ -1020,7 +1033,7 @@ GlobalObject::initModuleProto(JSContext* cx, Handle<GlobalObject*> global)
static const JSPropertySpec protoAccessors[] = {
JS_PSG("namespace", ModuleObject_namespace_Getter, 0),
JS_PSG("status", ModuleObject_statusGetter, 0),
JS_PSG("error", ModuleObject_errorGetter, 0),
JS_PSG("evaluationError", ModuleObject_evaluationErrorGetter, 0),
JS_PSG("requestedModules", ModuleObject_requestedModulesGetter, 0),
JS_PSG("importEntries", ModuleObject_importEntriesGetter, 0),
JS_PSG("localExportEntries", ModuleObject_localExportEntriesGetter, 0),
+16 -17
View File
@@ -7,6 +7,8 @@
#ifndef builtin_ModuleObject_h
#define builtin_ModuleObject_h
#include "mozilla/Maybe.h"
#include "jsapi.h"
#include "jsatom.h"
@@ -102,27 +104,27 @@ typedef Handle<ExportEntryObject*> HandleExportEntryObject;
class IndirectBindingMap
{
public:
explicit IndirectBindingMap(Zone* zone);
bool init();
void trace(JSTracer* trc);
bool putNew(JSContext* cx, HandleId name,
HandleModuleEnvironmentObject environment, HandleId localName);
bool put(JSContext* cx, HandleId name,
HandleModuleEnvironmentObject environment, HandleId localName);
size_t count() const {
return map_.count();
return map_ ? map_->count() : 0;
}
bool has(jsid name) const {
return map_.has(name);
return map_ ? map_->has(name) : false;
}
bool lookup(jsid name, ModuleEnvironmentObject** envOut, Shape** shapeOut) const;
template <typename Func>
void forEachExportedName(Func func) const {
for (auto r = map_.all(); !r.empty(); r.popFront())
if (!map_)
return;
for (auto r = map_->all(); !r.empty(); r.popFront())
func(r.front().key());
}
@@ -136,7 +138,7 @@ class IndirectBindingMap
typedef HashMap<jsid, Binding, DefaultHasher<jsid>, ZoneAllocPolicy> Map;
Map map_;
mozilla::Maybe<Map> map_;
};
class ModuleNamespaceObject : public ProxyObject
@@ -214,11 +216,10 @@ class ModuleObject : public NativeObject
enum
{
ScriptSlot = 0,
InitialEnvironmentSlot,
EnvironmentSlot,
NamespaceSlot,
StatusSlot,
ErrorSlot,
EvaluationErrorSlot,
HostDefinedSlot,
RequestedModulesSlot,
ImportEntriesSlot,
@@ -238,8 +239,8 @@ class ModuleObject : public NativeObject
"EnvironmentSlot must match self-hosting define");
static_assert(StatusSlot == MODULE_OBJECT_STATUS_SLOT,
"StatusSlot must match self-hosting define");
static_assert(ErrorSlot == MODULE_OBJECT_ERROR_SLOT,
"ErrorSlot must match self-hosting define");
static_assert(EvaluationErrorSlot == MODULE_OBJECT_EVALUATION_ERROR_SLOT,
"EvaluationErrorSlot must match self-hosting define");
static_assert(DFSIndexSlot == MODULE_OBJECT_DFS_INDEX_SLOT,
"DFSIndexSlot must match self-hosting define");
static_assert(DFSAncestorIndexSlot == MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT,
@@ -269,7 +270,8 @@ class ModuleObject : public NativeObject
ModuleEnvironmentObject* environment() const;
ModuleNamespaceObject* namespace_();
ModuleStatus status() const;
Value error() const;
bool hadEvaluationError() const;
Value evaluationError() const;
Value hostDefinedField() const;
ArrayObject& requestedModules() const;
ArrayObject& importEntries() const;
@@ -285,9 +287,6 @@ class ModuleObject : public NativeObject
void setHostDefinedField(const JS::Value& value);
// For intrinsic_CreateModuleEnvironment.
void createEnvironment();
// For BytecodeEmitter.
bool noteFunctionDeclaration(ExclusiveContext* cx, HandleAtom name, HandleFunction fun);
+11 -11
View File
@@ -97,17 +97,17 @@
#define REGEXP_STRING_ITERATOR_FLAGS_SLOT 2
#define REGEXP_STRING_ITERATOR_DONE_SLOT 3
#define MODULE_OBJECT_ENVIRONMENT_SLOT 2
#define MODULE_OBJECT_STATUS_SLOT 4
#define MODULE_OBJECT_ERROR_SLOT 5
#define MODULE_OBJECT_DFS_INDEX_SLOT 16
#define MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT 17
#define MODULE_OBJECT_ENVIRONMENT_SLOT 1
#define MODULE_OBJECT_STATUS_SLOT 3
#define MODULE_OBJECT_EVALUATION_ERROR_SLOT 4
#define MODULE_OBJECT_DFS_INDEX_SLOT 15
#define MODULE_OBJECT_DFS_ANCESTOR_INDEX_SLOT 16
#define MODULE_STATUS_ERRORED 0
#define MODULE_STATUS_UNINSTANTIATED 1
#define MODULE_STATUS_INSTANTIATING 2
#define MODULE_STATUS_INSTANTIATED 3
#define MODULE_STATUS_EVALUATING 4
#define MODULE_STATUS_EVALUATED 5
#define MODULE_STATUS_UNINSTANTIATED 0
#define MODULE_STATUS_INSTANTIATING 1
#define MODULE_STATUS_INSTANTIATED 2
#define MODULE_STATUS_EVALUATING 3
#define MODULE_STATUS_EVALUATED 4
#define MODULE_STATUS_EVALUATED_ERROR 5
#endif
+6 -2
View File
@@ -3566,8 +3566,6 @@ GetModuleEnvironment(JSContext* cx, HandleValue moduleValue)
// before they have been instantiated.
RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
MOZ_ASSERT(env);
MOZ_ASSERT_IF(module->environment(), module->environment() == env);
return env;
}
@@ -3585,6 +3583,9 @@ GetModuleEnvironmentNames(JSContext* cx, unsigned argc, Value* vp)
return false;
}
//- if (module->status() == MODULE_STATUS_ERRORED) {
//+ if (module->hadEvaluationError()) {
RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0]));
Rooted<IdVector> ids(cx, IdVector(cx));
if (!JS_Enumerate(cx, env, &ids))
@@ -3622,6 +3623,9 @@ GetModuleEnvironmentValue(JSContext* cx, unsigned argc, Value* vp)
return false;
}
//- if (module->status() == MODULE_STATUS_ERRORED) {
//+ if (module->hadEvaluationError()) {
RootedModuleEnvironmentObject env(cx, GetModuleEnvironment(cx, args[0]));
RootedString name(cx, args[1].toString());
RootedId id(cx);
+5
View File
@@ -2267,6 +2267,8 @@ void
js::gc::StoreBuffer::SlotsEdge::trace(TenuringTracer& mover) const
{
NativeObject* obj = object();
if(!IsCellPointerValid(obj))
return;
// Beware JSObject::swap exchanging a native object for a non-native one.
if (!obj->isNative())
@@ -2336,6 +2338,8 @@ js::gc::StoreBuffer::traceWholeCells(TenuringTracer& mover)
{
for (ArenaCellSet* cells = bufferWholeCell; cells; cells = cells->next) {
Arena* arena = cells->arena;
if(!IsCellPointerValid(arena))
continue;
MOZ_ASSERT(arena->bufferedCells == cells);
arena->bufferedCells = &ArenaCellSet::Empty;
@@ -2364,6 +2368,7 @@ js::gc::StoreBuffer::CellPtrEdge::trace(TenuringTracer& mover) const
{
if (!*edge)
return;
// XXX: We should check if the cell pointer is valid here too
MOZ_ASSERT((*edge)->getTraceKind() == JS::TraceKind::Object);
mover.traverse(reinterpret_cast<JSObject**>(edge));
+4 -8
View File
@@ -1,9 +1,8 @@
// This tests that attempting to perform ModuleDeclarationInstantation a second
// time after a failure re-throws the same error.
// This tests that module instantiation can succeed when executed a second
// time after a failure.
//
// The first attempt fails becuase module 'a' is not available. The second
// attempt fails because of the previous failure (it would otherwise succeed as
// 'a' is now available).
// attempt succeeds as 'a' is now available.
load(libdir + "dummyModuleResolveHook.js");
@@ -25,12 +24,9 @@ let a = moduleRepo['a'] = parseModule("export var a = 1; export var b = 2;");
let d = moduleRepo['d'] = parseModule("import { a } from 'c'; a;");
threw = false;
let e2;
try {
d.declarationInstantiation();
} catch (exc) {
threw = true;
e2 = exc;
}
assertEq(threw, true);
assertEq(e1, e2);
assertEq(threw, false);
@@ -0,0 +1,19 @@
// Test re-instantiation module after failure.
load(libdir + "asserts.js");
load(libdir + "dummyModuleResolveHook.js");
moduleRepo["good"] = parseModule(`export let x`);
moduleRepo["y1"] = parseModule(`export let y`);
moduleRepo["y2"] = parseModule(`export let y`);
moduleRepo["bad"] = parseModule(`export* from "y1"; export* from "y2";`);
moduleRepo["a"] = parseModule(`import* as ns from "good"; import {y} from "bad";`);
let b = moduleRepo["b"] = parseModule(`import "a";`);
let c = moduleRepo["c"] = parseModule(`import "a";`);
assertThrowsInstanceOf(() => b.declarationInstantiation(), SyntaxError);
assertThrowsInstanceOf(() => c.declarationInstantiation(), SyntaxError);
@@ -0,0 +1,9 @@
if (!('stackTest' in this))
quit();
let a = parseModule(`throw new Error`);
a.declarationInstantiation();
stackTest(function() {
a.evaluation();
});
@@ -0,0 +1,16 @@
load(libdir + "asserts.js");
load(libdir + "dummyModuleResolveHook.js");
moduleRepo["a"] = parseModule(`throw undefined`);
let b = moduleRepo["b"] = parseModule(`import "a";`);
let c = moduleRepo["c"] = parseModule(`import "a";`);
b.declarationInstantiation();
c.declarationInstantiation();
let count = 0;
try { b.evaluation() } catch (e) { count++; }
try { c.evaluation() } catch (e) { count++; }
assertEq(count, 2);
@@ -0,0 +1,19 @@
// Test re-instantiation module after failure.
load(libdir + "asserts.js");
load(libdir + "dummyModuleResolveHook.js");
moduleRepo["good"] = parseModule(`export let x`);
moduleRepo["y1"] = parseModule(`export let y`);
moduleRepo["y2"] = parseModule(`export let y`);
moduleRepo["bad"] = parseModule(`export* from "y1"; export* from "y2";`);
moduleRepo["a"] = parseModule(`import {x} from "good"; import {y} from "bad";`);
let b = moduleRepo["b"] = parseModule(`import "a";`);
let c = moduleRepo["c"] = parseModule(`import "a";`);
assertThrowsInstanceOf(() => b.declarationInstantiation(), SyntaxError);
assertThrowsInstanceOf(() => c.declarationInstantiation(), SyntaxError);
-1
View File
@@ -579,7 +579,6 @@ MSG_DEF(JSMSG_MISSING_IMPORT, 0, JSEXN_SYNTAXERR, "import not found")
MSG_DEF(JSMSG_AMBIGUOUS_IMPORT, 0, JSEXN_SYNTAXERR, "ambiguous import")
MSG_DEF(JSMSG_MISSING_NAMESPACE_EXPORT, 0, JSEXN_SYNTAXERR, "export not found for namespace")
MSG_DEF(JSMSG_MISSING_EXPORT, 1, JSEXN_SYNTAXERR, "local binding for export '{0}' not found")
MSG_DEF(JSMSG_MODULE_INSTANTIATE_FAILED, 0, JSEXN_INTERNALERR, "attempt to re-instantiate module after failure")
MSG_DEF(JSMSG_BAD_MODULE_STATUS, 0, JSEXN_INTERNALERR, "module record has unexpected status")
// Promise
+10 -22
View File
@@ -483,6 +483,11 @@ JS_DestroyContext(JSContext* cx)
DestroyContext(cx);
}
JS_PUBLIC_API(JSRuntime*)
JS_GetRuntime(JSContext* cx) {
return cx->runtime();
}
static JS_CurrentEmbedderTimeFunction currentEmbedderTimeFunction;
JS_PUBLIC_API(void)
@@ -4662,21 +4667,16 @@ JS::Evaluate(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return ::Evaluate(cx, optionsArg, filename, rval);
}
JS_PUBLIC_API(JSFunction*)
JS::GetModuleResolveHook(JSContext* cx)
JS_PUBLIC_API(JS::ModuleResolveHook)
JS::GetModuleResolveHook(JSRuntime* rt)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
return cx->global()->moduleResolveHook();
return rt->moduleResolveHook;
}
JS_PUBLIC_API(void)
JS::SetModuleResolveHook(JSContext* cx, HandleFunction func)
JS::SetModuleResolveHook(JSRuntime* rt, JS::ModuleResolveHook func)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, func);
cx->global()->setModuleResolveHook(func);
rt->moduleResolveHook = func;
}
JS_PUBLIC_API(bool)
@@ -4739,18 +4739,6 @@ JS::GetModuleScript(JSContext* cx, JS::HandleObject moduleArg)
return moduleArg->as<ModuleObject>().script();
}
JS_PUBLIC_API(bool)
JS::IsModuleErrored(JSObject* moduleArg)
{
return moduleArg->as<ModuleObject>().status() == MODULE_STATUS_ERRORED;
}
JS_PUBLIC_API(JS::Value)
JS::GetModuleError(JSObject* moduleArg)
{
return moduleArg->as<ModuleObject>().error();
}
JS_PUBLIC_API(JSObject*)
JS_New(JSContext* cx, HandleObject ctor, const JS::HandleValueArray& inputArgs)
{
+12 -13
View File
@@ -995,6 +995,9 @@ JS_NewContext(uint32_t maxbytes,
extern JS_PUBLIC_API(void)
JS_DestroyContext(JSContext* cx);
extern JS_PUBLIC_API(JSRuntime*)
JS_GetRuntime(JSContext* cx);
typedef double (*JS_CurrentEmbedderTimeFunction)();
/**
@@ -4322,17 +4325,19 @@ extern JS_PUBLIC_API(bool)
Evaluate(JSContext* cx, const ReadOnlyCompileOptions& options,
const char* filename, JS::MutableHandleValue rval);
/**
* Get the HostResolveImportedModule hook for a global.
*/
extern JS_PUBLIC_API(JSFunction*)
GetModuleResolveHook(JSContext* cx);
using ModuleResolveHook = JSObject* (*)(JSContext*, HandleObject, HandleString);
/**
* Set the HostResolveImportedModule hook for a global to the given function.
* Get the HostResolveImportedModule hook for the runtime.
*/
extern JS_PUBLIC_API(ModuleResolveHook)
GetModuleResolveHook(JSRuntime* rt);
/**
* Set the HostResolveImportedModule hook for the runtime to the given function.
*/
extern JS_PUBLIC_API(void)
SetModuleResolveHook(JSContext* cx, JS::HandleFunction func);
SetModuleResolveHook(JSRuntime* rt, ModuleResolveHook func);
/**
* Parse the given source buffer as a module in the scope of the current global
@@ -4395,12 +4400,6 @@ GetRequestedModules(JSContext* cx, JS::HandleObject moduleRecord);
extern JS_PUBLIC_API(JSScript*)
GetModuleScript(JSContext* cx, JS::HandleObject moduleRecord);
extern JS_PUBLIC_API(bool)
IsModuleErrored(JSObject* moduleRecord);
extern JS_PUBLIC_API(JS::Value)
GetModuleError(JSObject* moduleRecord);
} /* namespace JS */
extern JS_PUBLIC_API(bool)
+1 -1
View File
@@ -687,8 +687,8 @@ if CONFIG['_MSC_VER']:
elif CONFIG['CPU_ARCH'] == 'x86_64' and CONFIG['JS_HAS_CTYPES']:
SOURCES['ctypes/CTypes.cpp'].no_pgo = True # Bug 810661
# Prevent floating point errors caused by VC++ optimizations
# XXX We should add this to CXXFLAGS, too?
CFLAGS += ['-fp:precise']
CXXFLAGS += ['-fp:precise']
# C4805 warns mixing bool with other integral types in computation.
# But given the conversion from bool is specified, and this is a
# pattern widely used in code in js/src, suppress this warning here.
+29 -4
View File
@@ -274,6 +274,7 @@ struct ShellContext
JS::PersistentRooted<JobQueue> jobQueue;
ExclusiveData<ShellAsyncTasks> asyncTasks;
bool drainingJobQueue;
JS::PersistentRootedFunction moduleResolveHook;
/*
* Watchdog thread state.
@@ -439,7 +440,8 @@ ShellContext::ShellContext(JSContext* cx)
exitCode(0),
quitting(false),
readLineBufPos(0),
spsProfilingStackSize(0)
spsProfilingStackSize(0),
moduleResolveHook(cx)
{}
static ShellContext*
@@ -4030,13 +4032,34 @@ SetModuleResolveHook(JSContext* cx, unsigned argc, Value* vp)
return false;
}
RootedFunction hook(cx, &args[0].toObject().as<JSFunction>());
Rooted<GlobalObject*> global(cx, cx->global());
global->setModuleResolveHook(hook);
ShellContext* sc = GetShellContext(cx);
sc->moduleResolveHook = &args[0].toObject().as<JSFunction>();
args.rval().setUndefined();
return true;
}
static JSObject*
CallModuleResolveHook(JSContext* cx, HandleObject module, HandleString specifier)
{
ShellContext* sc = GetShellContext(cx);
JS::AutoValueArray<2> args(cx);
args[0].setObject(*module);
args[1].setString(specifier);
RootedValue result(cx);
if (!JS_CallFunction(cx, nullptr, sc->moduleResolveHook, args, &result))
return nullptr;
if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
return nullptr;
}
return &result.toObject();
}
static bool
GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp)
{
@@ -7962,6 +7985,8 @@ main(int argc, char** argv, char** envp)
js::SetPreserveWrapperCallback(cx, DummyPreserveWrapperCallback);
JS::SetModuleResolveHook(cx->runtime(), CallModuleResolveHook);
result = Shell(cx, &op, envp);
#ifdef DEBUG
+1 -1
View File
@@ -491,7 +491,7 @@ ModuleEnvironmentObject::createImportBinding(JSContext* cx, HandleAtom importNam
RootedId importNameId(cx, AtomToId(importName));
RootedId localNameId(cx, AtomToId(localName));
RootedModuleEnvironmentObject env(cx, &module->initialEnvironment());
if (!importBindings().putNew(cx, importNameId, env, localNameId)) {
if (!importBindings().put(cx, importNameId, env, localNameId)) {
ReportOutOfMemory(cx);
return false;
}
-14
View File
@@ -119,7 +119,6 @@ class GlobalObject : public NativeObject
DEBUGGERS,
INTRINSICS,
FOR_OF_PIC_CHAIN,
MODULE_RESOLVE_HOOK,
WINDOW_PROXY,
GLOBAL_THIS_RESOLVED,
@@ -879,19 +878,6 @@ class GlobalObject : public NativeObject
setReservedSlot(WINDOW_PROXY, ObjectValue(*windowProxy));
}
void setModuleResolveHook(HandleFunction hook) {
MOZ_ASSERT(hook);
setSlot(MODULE_RESOLVE_HOOK, ObjectValue(*hook));
}
JSFunction* moduleResolveHook() {
Value value = getSlotRef(MODULE_RESOLVE_HOOK);
if (value.isUndefined())
return nullptr;
return &value.toObject().as<JSFunction>();
}
// Returns either this global's star-generator function prototype, or null
// if that object was never created. Dodgy; for use only in also-dodgy
// GlobalHelperThreadState::mergeParseTaskCompartment().
+4 -2
View File
@@ -241,8 +241,10 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
lastAnimationTime(0),
performanceMonitoring(thisFromCtor()),
ionLazyLinkListSize_(0),
stackFormat_(parentRuntime ? js::StackFormat::Default
: js::StackFormat::SpiderMonkey)
stackFormat_(parentRuntime ?
js::StackFormat::Default :
js::StackFormat::SpiderMonkey),
moduleResolveHook()
{
setGCStoreBufferPtr(&gc.storeBuffer);
+3
View File
@@ -1294,6 +1294,9 @@ struct JSRuntime : public JS::shadow::Runtime,
// For inherited heap state accessors.
friend class js::gc::AutoTraceSession;
friend class JS::AutoEnterCycleCollection;
// The implementation-defined abstract operation HostResolveImportedModule.
JS::ModuleResolveHook moduleResolveHook;
};
namespace js {
+8 -20
View File
@@ -2026,36 +2026,26 @@ intrinsic_HostResolveImportedModule(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_ASSERT(args[0].toObject().is<ModuleObject>());
MOZ_ASSERT(args[1].isString());
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
RootedString specifier(cx, args[1].toString());
RootedFunction moduleResolveHook(cx, cx->global()->moduleResolveHook());
JS::ModuleResolveHook moduleResolveHook = cx->runtime()->moduleResolveHook;
if (!moduleResolveHook) {
JS_ReportErrorASCII(cx, "Module resolve hook not set");
return false;
}
RootedValue result(cx);
if (!JS_CallFunction(cx, nullptr, moduleResolveHook, args, &result))
RootedObject result(cx);
result = moduleResolveHook(cx, module, specifier);
if (!result)
return false;
if (!result.isObject() || !result.toObject().is<ModuleObject>()) {
if (!result->is<ModuleObject>()) {
JS_ReportErrorASCII(cx, "Module resolve hook did not return Module object");
return false;
}
args.rval().set(result);
return true;
}
static bool
intrinsic_CreateModuleEnvironment(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
RootedModuleObject module(cx, &args[0].toObject().as<ModuleObject>());
module->createEnvironment();
args.rval().setUndefined();
args.rval().setObject(*result);
return true;
}
@@ -2087,7 +2077,6 @@ intrinsic_CreateNamespaceBinding(JSContext* cx, unsigned argc, Value* vp)
// the slot directly.
RootedShape shape(cx, environment->lookup(cx, name));
MOZ_ASSERT(shape);
MOZ_ASSERT(environment->getSlot(shape->slot()).isMagic(JS_UNINITIALIZED_LEXICAL));
environment->setSlot(shape->slot(), args[2]);
args.rval().setUndefined();
return true;
@@ -2659,7 +2648,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
CallNonGenericSelfhostedMethod<Is<ModuleObject>>, 2, 0),
JS_FN("HostResolveImportedModule", intrinsic_HostResolveImportedModule, 2, 0),
JS_FN("IsModuleEnvironment", intrinsic_IsInstanceOfBuiltin<ModuleEnvironmentObject>, 1, 0),
JS_FN("CreateModuleEnvironment", intrinsic_CreateModuleEnvironment, 1, 0),
JS_FN("CreateImportBinding", intrinsic_CreateImportBinding, 4, 0),
JS_FN("CreateNamespaceBinding", intrinsic_CreateNamespaceBinding, 3, 0),
JS_FN("InstantiateModuleFunctionDeclarations",
+56 -32
View File
@@ -3546,10 +3546,10 @@ ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize,
imageSize.width = ComputeRoundedSize(imageSize.width, aBgPositioningArea.width);
if (!isRepeatRoundInBothDimensions &&
aLayerSize.mHeightType == nsStyleImageLayers::Size::DimensionType::eAuto) {
// Restore intrinsic rato
if (aIntrinsicSize.mRatio.width) {
float scale = float(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width;
imageSize.height = NSCoordSaturatingNonnegativeMultiply(imageSize.width, scale);
// Restore intrinsic ratio
if (aIntrinsicSize.mRatio) {
imageSize.height =
aIntrinsicSize.mRatio.Inverted().ApplyTo(imageSize.width);
}
}
}
@@ -3560,10 +3560,9 @@ ComputeDrawnSizeForBackground(const CSSSizeOrRatio& aIntrinsicSize,
imageSize.height = ComputeRoundedSize(imageSize.height, aBgPositioningArea.height);
if (!isRepeatRoundInBothDimensions &&
aLayerSize.mWidthType == nsStyleImageLayers::Size::DimensionType::eAuto) {
// Restore intrinsic rato
if (aIntrinsicSize.mRatio.height) {
float scale = float(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height;
imageSize.width = NSCoordSaturatingNonnegativeMultiply(imageSize.height, scale);
// Restore intrinsic ratio
if (aIntrinsicSize.mRatio) {
imageSize.width = aIntrinsicSize.mRatio.ApplyTo(imageSize.height);
}
}
}
@@ -5264,17 +5263,11 @@ CSSSizeOrRatio::ComputeConcreteSize() const
return nsSize(mWidth, mHeight);
}
if (mHasWidth) {
nscoord height = NSCoordSaturatingNonnegativeMultiply(
mWidth,
double(mRatio.height) / mRatio.width);
return nsSize(mWidth, height);
return nsSize(mWidth, mRatio.Inverted().ApplyTo(mWidth));
}
MOZ_ASSERT(mHasHeight);
nscoord width = NSCoordSaturatingNonnegativeMultiply(
mHeight,
double(mRatio.width) / mRatio.height);
return nsSize(width, mHeight);
return nsSize(mRatio.ApplyTo(mHeight), mHeight);
}
CSSSizeOrRatio
@@ -5297,6 +5290,16 @@ nsImageRenderer::ComputeIntrinsicSize()
if (haveHeight) {
result.SetHeight(nsPresContext::CSSPixelsToAppUnits(imageIntSize.height));
}
if (!haveHeight && haveWidth && result.mRatio) {
nscoord intrinsicHeight =
result.mRatio.Inverted().ApplyTo(imageIntSize.width);
result.SetHeight(nsPresContext::CSSPixelsToAppUnits(intrinsicHeight));
} else if (haveHeight && !haveWidth && result.mRatio) {
nscoord intrinsicWidth = result.mRatio.ApplyTo(imageIntSize.height);
result.SetWidth(nsPresContext::CSSPixelsToAppUnits(intrinsicWidth));
}
break;
}
case eStyleImageType_Element:
@@ -5379,9 +5382,7 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize,
if (aSpecifiedSize.mHasWidth) {
nscoord height;
if (aIntrinsicSize.HasRatio()) {
height = NSCoordSaturatingNonnegativeMultiply(
aSpecifiedSize.mWidth,
double(aIntrinsicSize.mRatio.height) / aIntrinsicSize.mRatio.width);
height = aIntrinsicSize.mRatio.Inverted().ApplyTo(aSpecifiedSize.mWidth);
} else if (aIntrinsicSize.mHasHeight) {
height = aIntrinsicSize.mHeight;
} else {
@@ -5393,9 +5394,7 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize,
MOZ_ASSERT(aSpecifiedSize.mHasHeight);
nscoord width;
if (aIntrinsicSize.HasRatio()) {
width = NSCoordSaturatingNonnegativeMultiply(
aSpecifiedSize.mHeight,
double(aIntrinsicSize.mRatio.width) / aIntrinsicSize.mRatio.height);
width = aIntrinsicSize.mRatio.ApplyTo(aSpecifiedSize.mHeight);
} else if (aIntrinsicSize.mHasWidth) {
width = aIntrinsicSize.mWidth;
} else {
@@ -5406,32 +5405,57 @@ nsImageRenderer::ComputeConcreteSize(const CSSSizeOrRatio& aSpecifiedSize,
/* static */ nsSize
nsImageRenderer::ComputeConstrainedSize(const nsSize& aConstrainingSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
FitType aFitType)
{
if (aIntrinsicRatio.width <= 0 && aIntrinsicRatio.height <= 0) {
if (!aIntrinsicRatio) {
return aConstrainingSize;
}
float scaleX = double(aConstrainingSize.width) / aIntrinsicRatio.width;
float scaleY = double(aConstrainingSize.height) / aIntrinsicRatio.height;
// Suppose we're doing a "contain" fit. If the image's aspect ratio has a
// "fatter" shape than the constraint area, then we need to use the
// constraint area's full width, and we need to use the aspect ratio to
// produce a height. ON the other hand, if the aspect ratio is "skinnier", we
// use the constraint area's full height, and we use the aspect ratio to
// produce a width. (If instead we're doing a "cover" fit, then it can easily
// be seen that we should do precisely the opposite.)
//
// This is equivalent to the more descriptive alternative:
//
// AspectRatio::FromSize(aConstrainingSize) < aIntrinsicRatio
//
// But gracefully handling the case where one of the two dimensions from
// aConstrainingSize is zero. This is easy to prove since:
//
// aConstrainingSize.width / aConstrainingSize.height < aIntrinsicRatio
//
// Is trivially equivalent to:
//
// aIntrinsicRatio.width < aIntrinsicRatio * aConstrainingSize.height
//
// For the cases where height is not zero.
//
// We use float math here to avoid losing precision for very lareg backgrounds
// since we use saturating nscoord math otherwise.
const float constraintWidth = float(aConstrainingSize.width);
const float hypotheticalWidth =
aIntrinsicRatio.ApplyToFloat(aConstrainingSize.height);
nsSize size;
if ((aFitType == CONTAIN) == (scaleX < scaleY)) {
if ((aFitType == CONTAIN) == (constraintWidth < hypotheticalWidth)) {
size.width = aConstrainingSize.width;
size.height = NSCoordSaturatingNonnegativeMultiply(
aIntrinsicRatio.height, scaleX);
size.height = aIntrinsicRatio.Inverted().ApplyTo(aConstrainingSize.width);
// If we're reducing the size by less than one css pixel, then just use the
// constraining size.
if (aFitType == CONTAIN && aConstrainingSize.height - size.height < nsPresContext::AppUnitsPerCSSPixel()) {
size.height = aConstrainingSize.height;
}
} else {
size.width = NSCoordSaturatingNonnegativeMultiply(
aIntrinsicRatio.width, scaleY);
size.height = aConstrainingSize.height;
size.width = aIntrinsicRatio.ApplyTo(aConstrainingSize.height);
if (aFitType == CONTAIN && aConstrainingSize.width - size.width < nsPresContext::AppUnitsPerCSSPixel()) {
size.width = aConstrainingSize.width;
}
size.height = aConstrainingSize.height;
}
return size;
}
+10 -12
View File
@@ -17,6 +17,7 @@
#include "nsLayoutUtils.h"
#include "nsStyleStruct.h"
#include "nsIFrame.h"
#include "mozilla/AspectRatio.h"
class gfxDrawable;
class nsStyleContext;
@@ -41,8 +42,7 @@ class ImageContainer;
struct CSSSizeOrRatio
{
CSSSizeOrRatio()
: mRatio(0, 0)
, mHasWidth(false)
: mHasWidth(false)
, mHasHeight(false) {}
bool CanComputeConcreteSize() const
@@ -50,12 +50,12 @@ struct CSSSizeOrRatio
return mHasWidth + mHasHeight + HasRatio() >= 2;
}
bool IsConcrete() const { return mHasWidth && mHasHeight; }
bool HasRatio() const { return mRatio.width > 0 && mRatio.height > 0; }
bool HasRatio() const { return !!mRatio; }
bool IsEmpty() const
{
return (mHasWidth && mWidth <= 0) ||
(mHasHeight && mHeight <= 0) ||
mRatio.width <= 0 || mRatio.height <= 0;
!mRatio;
}
// CanComputeConcreteSize must return true when ComputeConcreteSize is
@@ -67,7 +67,7 @@ struct CSSSizeOrRatio
mWidth = aWidth;
mHasWidth = true;
if (mHasHeight) {
mRatio = nsSize(mWidth, mHeight);
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
}
void SetHeight(nscoord aHeight)
@@ -75,7 +75,7 @@ struct CSSSizeOrRatio
mHeight = aHeight;
mHasHeight = true;
if (mHasWidth) {
mRatio = nsSize(mWidth, mHeight);
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
}
void SetSize(const nsSize& aSize)
@@ -84,16 +84,16 @@ struct CSSSizeOrRatio
mHeight = aSize.height;
mHasWidth = true;
mHasHeight = true;
mRatio = aSize;
mRatio = AspectRatio::FromSize(mWidth, mHeight);
}
void SetRatio(const nsSize& aRatio)
void SetRatio(const AspectRatio& aRatio)
{
MOZ_ASSERT(!mHasWidth || !mHasHeight,
"Probably shouldn't be setting a ratio if we have a concrete size");
mRatio = aRatio;
}
nsSize mRatio;
AspectRatio mRatio;
nscoord mWidth;
nscoord mHeight;
bool mHasWidth;
@@ -184,11 +184,9 @@ public:
/**
* Compute the size of the rendered image using either the 'cover' or
* 'contain' constraints (aFitType).
* aIntrinsicRatio may be an invalid ratio, that is one or both of its
* dimensions can be less than or equal to zero.
*/
static nsSize ComputeConstrainedSize(const nsSize& aConstrainingSize,
const nsSize& aIntrinsicRatio,
const mozilla::AspectRatio& aIntrinsicRatio,
FitType aFitType);
/**
* Compute the size of the rendered image (the concrete size) where no cover/
+26 -38
View File
@@ -4045,7 +4045,7 @@ nsLayoutUtils::GetTextShadowRectsUnion(const nsRect& aTextAndDecorationsRect,
enum ObjectDimensionType { eWidth, eHeight };
static nscoord
ComputeMissingDimension(const nsSize& aDefaultObjectSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
const Maybe<nscoord>& aSpecifiedWidth,
const Maybe<nscoord>& aSpecifiedHeight,
ObjectDimensionType aDimensionToCompute)
@@ -4056,21 +4056,15 @@ ComputeMissingDimension(const nsSize& aDefaultObjectSize,
// 1. "If the object has an intrinsic aspect ratio, the missing dimension of
// the concrete object size is calculated using the intrinsic aspect
// ratio and the present dimension."
if (aIntrinsicRatio.width > 0 && aIntrinsicRatio.height > 0) {
if (aIntrinsicRatio) {
// Fill in the missing dimension using the intrinsic aspect ratio.
nscoord knownDimensionSize;
float ratio;
if (aDimensionToCompute == eWidth) {
knownDimensionSize = *aSpecifiedHeight;
ratio = aIntrinsicRatio.width / aIntrinsicRatio.height;
} else {
knownDimensionSize = *aSpecifiedWidth;
ratio = aIntrinsicRatio.height / aIntrinsicRatio.width;
return aIntrinsicRatio.ApplyTo(*aSpecifiedHeight);
}
return NSCoordSaturatingNonnegativeMultiply(knownDimensionSize, ratio);
return aIntrinsicRatio.Inverted().ApplyTo(*aSpecifiedWidth);
}
// 2. "Otherwise, if the missing dimension is present in the object’s
// 2. "Otherwise, if the missing dimension is present in the object's
// intrinsic dimensions, [...]"
// NOTE: *Skipping* this case, because we already know it's not true -- we're
// in this function because the missing dimension is *not* present in
@@ -4108,7 +4102,7 @@ ComputeMissingDimension(const nsSize& aDefaultObjectSize,
static Maybe<nsSize>
MaybeComputeObjectFitNoneSize(const nsSize& aDefaultObjectSize,
const IntrinsicSize& aIntrinsicSize,
const nsSize& aIntrinsicRatio)
const AspectRatio& aIntrinsicRatio)
{
// "If the object has an intrinsic height or width, its size is resolved as
// if its intrinsic dimensions were given as the specified size."
@@ -4155,15 +4149,13 @@ MaybeComputeObjectFitNoneSize(const nsSize& aDefaultObjectSize,
static nsSize
ComputeConcreteObjectSize(const nsSize& aConstraintSize,
const IntrinsicSize& aIntrinsicSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
uint8_t aObjectFit)
{
// Handle default behavior (filling the container) w/ fast early return.
// (Also: if there's no valid intrinsic ratio, then we have the "fill"
// behavior & just use the constraint size.)
if (MOZ_LIKELY(aObjectFit == NS_STYLE_OBJECT_FIT_FILL) ||
aIntrinsicRatio.width == 0 ||
aIntrinsicRatio.height == 0) {
if (MOZ_LIKELY(aObjectFit == NS_STYLE_OBJECT_FIT_FILL) || !aIntrinsicRatio) {
return aConstraintSize;
}
@@ -4250,7 +4242,7 @@ HasInitialObjectFitAndPosition(const nsStylePosition* aStylePos)
/* static */ nsRect
nsLayoutUtils::ComputeObjectDestRect(const nsRect& aConstraintRect,
const IntrinsicSize& aIntrinsicSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
const nsStylePosition* aStylePos,
nsPoint* aAnchorPoint)
{
@@ -5172,10 +5164,12 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
styleMinBSize.GetCoordValue() == 0)) ||
styleMaxBSize.GetUnit() != eStyleUnit_None) {
nsSize ratio(aFrame->GetIntrinsicRatio());
nscoord ratioISize = (horizontalAxis ? ratio.width : ratio.height);
nscoord ratioBSize = (horizontalAxis ? ratio.height : ratio.width);
if (ratioBSize != 0) {
AspectRatio ratio = aFrame->GetIntrinsicRatio();
if (ratio) {
// Convert 'ratio' if necessary, so that it's storing ISize/BSize:
if (!horizontalAxis) {
ratio = ratio.Inverted();
}
AddStateBitToAncestors(aFrame,
NS_FRAME_DESCENDANT_INTRINSIC_ISIZE_DEPENDS_ON_BSIZE);
@@ -5191,14 +5185,14 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
result = NSCoordMulDiv(h, ratioISize, ratioBSize);
result = ratio.ApplyTo(h);
}
if (GetDefiniteSize(styleMaxBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord maxISize = NSCoordMulDiv(h, ratioISize, ratioBSize);
nscoord maxISize = ratio.ApplyTo(h);
if (maxISize < result) {
result = maxISize;
}
@@ -5211,7 +5205,7 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord minISize = NSCoordMulDiv(h, ratioISize, ratioBSize);
nscoord minISize = ratio.ApplyTo(h);
if (minISize > result) {
result = minISize;
}
@@ -6674,12 +6668,12 @@ nsLayoutUtils::DrawSingleImage(gfxContext& aContext,
/* static */ void
nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
CSSIntSize& aImageSize, /*outparam*/
nsSize& aIntrinsicRatio, /*outparam*/
AspectRatio& aIntrinsicRatio, /*outparam*/
bool& aGotWidth, /*outparam*/
bool& aGotHeight /*outparam*/)
{
aGotWidth = NS_SUCCEEDED(aImage->GetWidth(&aImageSize.width));
aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height));
aGotHeight = NS_SUCCEEDED(aImage->GetHeight(&aImageSize.height));
bool gotRatio = NS_SUCCEEDED(aImage->GetIntrinsicRatio(&aIntrinsicRatio));
if (!(aGotWidth && aGotHeight) && !gotRatio) {
@@ -6687,7 +6681,7 @@ nsLayoutUtils::ComputeSizeForDrawing(imgIContainer *aImage,
// decoded) and should return zero size.
aGotWidth = aGotHeight = true;
aImageSize = CSSIntSize(0, 0);
aIntrinsicRatio = nsSize(0, 0);
aIntrinsicRatio = AspectRatio();
}
}
@@ -6696,7 +6690,7 @@ nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage,
const nsSize& aFallbackSize)
{
CSSIntSize imageSize;
nsSize imageRatio;
AspectRatio imageRatio;
bool gotHeight, gotWidth;
ComputeSizeForDrawing(aImage, imageSize, imageRatio, gotWidth, gotHeight);
@@ -6704,19 +6698,13 @@ nsLayoutUtils::ComputeSizeForDrawingWithFallback(imgIContainer* aImage,
// intrinsic ratio of the image.
if (gotWidth != gotHeight) {
if (!gotWidth) {
if (imageRatio.height != 0) {
imageSize.width =
NSCoordSaturatingNonnegativeMultiply(imageSize.height,
float(imageRatio.width) /
float(imageRatio.height));
if (imageRatio) {
imageSize.width = imageRatio.ApplyTo(imageSize.height);
gotWidth = true;
}
} else {
if (imageRatio.width != 0) {
imageSize.height =
NSCoordSaturatingNonnegativeMultiply(imageSize.width,
float(imageRatio.height) /
float(imageRatio.width));
if (imageRatio) {
imageSize.height = imageRatio.Inverted().ApplyTo(imageSize.width);
gotHeight = true;
}
}
+4 -2
View File
@@ -65,6 +65,7 @@ struct nsStyleImageOrientation;
struct nsOverflowAreas;
namespace mozilla {
struct aspectRatio;
enum class CSSPseudoElementType : uint8_t;
class EventListenerManager;
class SVGImageContext;
@@ -126,6 +127,7 @@ enum class RelativeTo {
*/
class nsLayoutUtils
{
typedef mozilla::AspectRatio AspectRatio;
typedef mozilla::dom::DOMRectList DOMRectList;
typedef mozilla::layers::Layer Layer;
typedef mozilla::ContainerLayerParameters ContainerLayerParameters;
@@ -1258,7 +1260,7 @@ public:
*/
static nsRect ComputeObjectDestRect(const nsRect& aConstraintRect,
const IntrinsicSize& aIntrinsicSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
const nsStylePosition* aStylePos,
nsPoint* aAnchorPoint = nullptr);
@@ -1878,7 +1880,7 @@ public:
*/
static void ComputeSizeForDrawing(imgIContainer* aImage,
CSSIntSize& aImageSize,
nsSize& aIntrinsicRatio,
AspectRatio& aIntrinsicRatio,
bool& aGotWidth,
bool& aGotHeight);
+81
View File
@@ -0,0 +1,81 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_AspectRatio_h
#define mozilla_AspectRatio_h
/* The aspect ratio of a box, in a "width / height" format. */
#include "mozilla/Attributes.h"
#include "nsCoord.h"
#include <algorithm>
#include <limits>
namespace mozilla {
struct AspectRatio {
AspectRatio() : mRatio(0.0f) {}
explicit AspectRatio(float aRatio) : mRatio(std::max(aRatio, 0.0f)) {}
static AspectRatio FromSize(float aWidth, float aHeight) {
if (aWidth == 0.0f || aHeight == 0.0f) {
return AspectRatio();
}
return AspectRatio(aWidth / aHeight);
}
static AspectRatio FromSize(nsSize aSize) {
return FromSize(aSize.width, aSize.height);
}
static AspectRatio FromSize(nsIntSize aSize) {
return FromSize(aSize.width, aSize.height);
}
explicit operator bool() const { return mRatio != 0.0f; }
nscoord ApplyTo(nscoord aCoord) const {
MOZ_DIAGNOSTIC_ASSERT(*this);
return NSCoordSaturatingNonnegativeMultiply(aCoord, mRatio);
}
float ApplyToFloat(float aFloat) const {
MOZ_DIAGNOSTIC_ASSERT(*this);
return mRatio * aFloat;
}
// Inverts the ratio, in order to get the height / width ratio.
MOZ_MUST_USE AspectRatio Inverted() const {
if (!*this) {
return AspectRatio();
}
// Clamp to a small epsilon, in case mRatio is absurdly large & produces
// 0.0f in the division here (so that valid ratios always generate other
// valid ratios when inverted).
return AspectRatio(
std::max(std::numeric_limits<float>::epsilon(), 1.0f / mRatio));
}
bool operator==(const AspectRatio& aOther) const {
return mRatio == aOther.mRatio;
}
bool operator!=(const AspectRatio& aOther) const {
return !(*this == aOther);
}
bool operator<(const AspectRatio& aOther) const {
return mRatio < aOther.mRatio;
}
private:
// 0.0f represents no aspect ratio.
float mRatio;
};
} // namespace mozilla
#endif // mozilla_AspectRatio_h
+15
View File
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<script>
document.addEventListener('DOMContentLoaded', () => {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
svg.setAttribute('height', '6')
svg.setAttribute('width', '1pc')
document.documentElement.appendChild(svg)
svg.style.setProperty('height', '5%', undefined)
svg.width.baseVal.valueInSpecifiedUnits = 1.988164037240853e+38
})
</script>
</head>
</html>
@@ -642,3 +642,4 @@ load 1278461-1.html
load 1278461-2.html
load 1304441.html
load 1316649.html
load 1633434.html
+1
View File
@@ -109,6 +109,7 @@ EXPORTS += [
]
EXPORTS.mozilla += [
'AspectRatio.h',
'CSSAlignUtils.h',
'ReflowInput.h',
'ReflowOutput.h',
+14 -17
View File
@@ -557,8 +557,8 @@ public:
return mFlexShrink * mFlexBaseSize;
}
const nsSize& IntrinsicRatio() const { return mIntrinsicRatio; }
bool HasIntrinsicRatio() const { return mIntrinsicRatio != nsSize(); }
const AspectRatio IntrinsicRatio() const { return mIntrinsicRatio; }
bool HasIntrinsicRatio() const { return !!mIntrinsicRatio; }
// Getters for margin:
// ===================
@@ -756,7 +756,7 @@ protected:
const float mFlexGrow;
const float mFlexShrink;
const nsSize mIntrinsicRatio;
const AspectRatio mIntrinsicRatio;
const nsMargin mBorderPadding;
nsMargin mMargin; // non-const because we need to resolve auto margins
@@ -1520,22 +1520,20 @@ CrossSizeToUseWithRatio(const FlexItem& aFlexItem,
}
// Convenience function; returns a main-size, given a cross-size and an
// intrinsic ratio. The intrinsic ratio must not have 0 in its cross-axis
// component (or else we'll divide by 0).
// intrinsic ratio. The caller is responsible for ensuring that the passed-in
// intrinsic ratio is not zero.
static nscoord
MainSizeFromAspectRatio(nscoord aCrossSize,
const nsSize& aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
const FlexboxAxisTracker& aAxisTracker)
{
MOZ_ASSERT(aAxisTracker.GetCrossComponent(aIntrinsicRatio) != 0,
MOZ_ASSERT(aIntrinsicRatio,
"Invalid ratio; will divide by 0! Caller should've checked...");
AspectRatio ratio = aAxisTracker.IsMainAxisHorizontal() ?
aIntrinsicRatio :
aIntrinsicRatio.Inverted();
if (aAxisTracker.IsCrossAxisHorizontal()) {
// cross axis horiz --> aCrossSize is a width. Converting to height.
return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.height, aIntrinsicRatio.width);
}
// cross axis vert --> aCrossSize is a height. Converting to width.
return NSCoordMulDiv(aCrossSize, aIntrinsicRatio.width, aIntrinsicRatio.height);
return ratio.ApplyTo(aCrossSize);
}
// Partially resolves "min-[width|height]:auto" and returns the resulting value.
@@ -1584,7 +1582,7 @@ PartiallyResolveAutoMinSize(const FlexItem& aFlexItem,
// * if the item has an intrinsic aspect ratio, the width (height) calculated
// from the aspect ratio and any definite size constraints in the opposite
// dimension.
if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) {
if (aFlexItem.IntrinsicRatio()) {
// We have a usable aspect ratio. (not going to divide by 0)
const bool useMinSizeIfCrossSizeIsIndefinite = true;
nscoord crossSizeToUseWithRatio =
@@ -1617,7 +1615,7 @@ ResolveAutoFlexBasisFromRatio(FlexItem& aFlexItem,
// - a definite cross size
// then the flex base size is calculated from its inner cross size and the
// flex item’s intrinsic aspect ratio.
if (aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) != 0) {
if (aFlexItem.IntrinsicRatio()) {
// We have a usable aspect ratio. (not going to divide by 0)
const bool useMinSizeIfCrossSizeIsIndefinite = false;
nscoord crossSizeToUseWithRatio =
@@ -1693,8 +1691,7 @@ nsFlexContainerFrame::
// (We'll consider that later, if we need to.)
resolvedMinSize = PartiallyResolveAutoMinSize(aFlexItem, aItemReflowInput,
aAxisTracker);
if (resolvedMinSize > 0 &&
aAxisTracker.GetCrossComponent(aFlexItem.IntrinsicRatio()) == 0) {
if (resolvedMinSize > 0 && !aFlexItem.IntrinsicRatio()) {
// We don't have a usable aspect ratio, so we need to consider our
// min-content size as another candidate min-size, which we'll have to
// min() with the current resolvedMinSize.
+24 -33
View File
@@ -4643,10 +4643,10 @@ nsFrame::GetIntrinsicSize()
return IntrinsicSize(); // default is width/height set to eStyleUnit_None
}
/* virtual */ nsSize
/* virtual */ AspectRatio
nsFrame::GetIntrinsicRatio()
{
return nsSize(0, 0);
return AspectRatio();
}
/* virtual */
@@ -4660,7 +4660,7 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
const LogicalSize& aPadding,
ComputeSizeFlags aFlags)
{
MOZ_ASSERT(GetIntrinsicRatio() == nsSize(0,0),
MOZ_ASSERT(!GetIntrinsicRatio(),
"Please override this method and call "
"nsFrame::ComputeSizeWithIntrinsicDimensions instead.");
LogicalSize result = ComputeAutoSize(aRenderingContext, aWM,
@@ -4916,13 +4916,15 @@ LogicalSize
nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingContext,
WritingMode aWM,
const IntrinsicSize& aIntrinsicSize,
nsSize aIntrinsicRatio,
const AspectRatio& aIntrinsicRatio,
const LogicalSize& aCBSize,
const LogicalSize& aMargin,
const LogicalSize& aBorder,
const LogicalSize& aPadding,
ComputeSizeFlags aFlags)
{
auto logicalRatio =
aWM.IsVertical() ? aIntrinsicRatio.Inverted() : aIntrinsicRatio;
const nsStylePosition* stylePos = StylePosition();
const nsStyleCoord* inlineStyleCoord = &stylePos->ISize(aWM);
const nsStyleCoord* blockStyleCoord = &stylePos->BSize(aWM);
@@ -5183,10 +5185,6 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
intrinsicBSize = 0;
}
NS_ASSERTION(aIntrinsicRatio.width >= 0 && aIntrinsicRatio.height >= 0,
"Intrinsic ratio has a negative component!");
LogicalSize logicalRatio(aWM, aIntrinsicRatio);
// Now calculate the used values for iSize and bSize:
if (isAutoISize) {
@@ -5200,9 +5198,9 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
if (hasIntrinsicISize) {
tentISize = intrinsicISize;
} else if (hasIntrinsicBSize && logicalRatio.BSize(aWM) > 0) {
tentISize = NSCoordMulDiv(intrinsicBSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
} else if (logicalRatio.ISize(aWM) > 0) {
} else if (hasIntrinsicBSize && logicalRatio) {
tentISize = logicalRatio.ApplyTo(intrinsicBSize);
} else if (logicalRatio) {
tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
if (tentISize < 0) tentISize = 0;
} else {
@@ -5219,8 +5217,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
if (hasIntrinsicBSize) {
tentBSize = intrinsicBSize;
} else if (logicalRatio.ISize(aWM) > 0) {
tentBSize = NSCoordMulDiv(tentISize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
} else if (logicalRatio) {
tentBSize = logicalRatio.Inverted().ApplyTo(tentISize);
} else {
tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
}
@@ -5231,46 +5229,39 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
}
if (aIntrinsicRatio != nsSize(0, 0)) {
if (logicalRatio) {
if (stretchI == eStretch) {
tentISize = iSize; // * / 'stretch'
if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / 'stretch'
} else if (stretchB == eStretchPreservingRatio && logicalRatio.ISize(aWM) > 0) {
} else if (stretchB == eStretchPreservingRatio) {
// 'normal' / 'stretch'
tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
}
} else if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / * (except 'stretch')
if (stretchI == eStretchPreservingRatio && logicalRatio.BSize(aWM) > 0) {
if (stretchI == eStretchPreservingRatio) {
// 'stretch' / 'normal'
tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchI == eStretchPreservingRatio) {
tentISize = iSize; // * (except 'stretch') / 'normal'
if (logicalRatio.ISize(aWM) > 0) {
tentBSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
}
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
// Stretch within the CB size with preserved intrinsic ratio.
tentBSize = bSize; // 'normal' / 'normal'
if (logicalRatio.BSize(aWM) > 0) {
tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
}
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchB == eStretchPreservingRatio) {
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
if (logicalRatio.BSize(aWM) > 0) {
tentISize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
}
tentISize = logicalRatio.ApplyTo(bSize);
}
}
// ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when applying
// the min/max-size. We don't want that when we have 'stretch' in either
// axis because tentISize/tentBSize is likely not according to ratio now.
if (aIntrinsicRatio != nsSize(0, 0) &&
stretchI != eStretch && stretchB != eStretch) {
if (logicalRatio && stretchI != eStretch && stretchB != eStretch) {
nsSize autoSize = nsLayoutUtils::
ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
maxISize, maxBSize,
@@ -5291,8 +5282,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
// 'auto' iSize, non-'auto' bSize
bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
if (stretchI != eStretch) {
if (logicalRatio.BSize(aWM) > 0) {
iSize = NSCoordMulDiv(bSize, logicalRatio.ISize(aWM), logicalRatio.BSize(aWM));
if (logicalRatio) {
iSize = logicalRatio.ApplyTo(bSize);
} else if (hasIntrinsicISize) {
if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
intrinsicISize > iSize)) {
@@ -5311,8 +5302,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
// non-'auto' iSize, 'auto' bSize
iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
if (stretchB != eStretch) {
if (logicalRatio.ISize(aWM) > 0) {
bSize = NSCoordMulDiv(iSize, logicalRatio.BSize(aWM), logicalRatio.ISize(aWM));
if (logicalRatio) {
bSize = logicalRatio.Inverted().ApplyTo(iSize);
} else if (hasIntrinsicBSize) {
if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
intrinsicBSize > bSize)) {
+2 -2
View File
@@ -264,7 +264,7 @@ public:
IntrinsicISizeOffsetData
IntrinsicISizeOffsets(nscoord aPercentageBasis = NS_UNCONSTRAINEDSIZE) override;
virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
virtual nsSize GetIntrinsicRatio() override;
virtual mozilla::AspectRatio GetIntrinsicRatio() override;
virtual mozilla::LogicalSize
ComputeSize(nsRenderingContext* aRenderingContext,
@@ -285,7 +285,7 @@ public:
nsRenderingContext* aRenderingContext,
mozilla::WritingMode aWM,
const mozilla::IntrinsicSize& aIntrinsicSize,
nsSize aIntrinsicRatio,
const mozilla::AspectRatio& aIntrinsicRatio,
const mozilla::LogicalSize& aCBSize,
const mozilla::LogicalSize& aMargin,
const mozilla::LogicalSize& aBorder,
+11 -20
View File
@@ -44,21 +44,6 @@ IntrinsicSizeFromCanvasSize(const nsIntSize& aCanvasSizeInPx)
return intrinsicSize;
}
/* Helper for our nsIFrame::GetIntrinsicRatio() impl. Takes the result of
* "GetCanvasSize()" as a parameter, which may help avoid redundant
* indirect calls to GetCanvasSize().
*
* @param aCanvasSizeInPx The canvas's size in CSS pixels, as returned
* by GetCanvasSize().
* @return The canvas's intrinsic ratio, as a nsSize.
*/
static nsSize
IntrinsicRatioFromCanvasSize(const nsIntSize& aCanvasSizeInPx)
{
return nsSize(nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.width),
nsPresContext::CSSPixelsToAppUnits(aCanvasSizeInPx.height));
}
class nsDisplayCanvas : public nsDisplayItem {
public:
nsDisplayCanvas(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
@@ -92,7 +77,7 @@ public:
// Need intrinsic size & ratio, for ComputeObjectDestRect:
nsIntSize canvasSize = f->GetCanvasSize();
IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSize);
nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSize);
AspectRatio intrinsicRatio = AspectRatio::FromSize(canvasSize);
const nsRect destRect =
nsLayoutUtils::ComputeObjectDestRect(constraintRect,
@@ -211,10 +196,16 @@ nsHTMLCanvasFrame::GetIntrinsicSize()
return IntrinsicSizeFromCanvasSize(GetCanvasSize());
}
/* virtual */ nsSize
/* virtual */ AspectRatio
nsHTMLCanvasFrame::GetIntrinsicRatio()
{
return IntrinsicRatioFromCanvasSize(GetCanvasSize());
// When 'contain: size' is implemented, make sure to check for it.
/*
if (StyleDisplay()->IsContainSize()) {
return AspectRatio();
}
*/
return AspectRatio::FromSize(GetCanvasSize());
}
/* virtual */
@@ -234,7 +225,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext,
intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width));
intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height));
nsSize intrinsicRatio = GetIntrinsicRatio(); // won't actually be used
AspectRatio intrinsicRatio = GetIntrinsicRatio();
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, intrinsicRatio,
@@ -340,7 +331,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
return nullptr;
IntrinsicSize intrinsicSize = IntrinsicSizeFromCanvasSize(canvasSizeInPx);
nsSize intrinsicRatio = IntrinsicRatioFromCanvasSize(canvasSizeInPx);
AspectRatio intrinsicRatio = AspectRatio::FromSize(canvasSizeInPx);
nsRect dest =
nsLayoutUtils::ComputeObjectDestRect(area, intrinsicSize, intrinsicRatio,
+1 -1
View File
@@ -58,7 +58,7 @@ public:
virtual nscoord GetMinISize(nsRenderingContext *aRenderingContext) override;
virtual nscoord GetPrefISize(nsRenderingContext *aRenderingContext) override;
virtual mozilla::IntrinsicSize GetIntrinsicSize() override;
virtual nsSize GetIntrinsicRatio() override;
virtual mozilla::AspectRatio GetIntrinsicRatio() override;
virtual mozilla::LogicalSize
ComputeSize(nsRenderingContext *aRenderingContext,
+7 -7
View File
@@ -27,6 +27,7 @@
#include "FrameProperties.h"
#include "LayoutConstants.h"
#include "mozilla/layout/FrameChildList.h"
#include "mozilla/AspectRatio.h"
#include "mozilla/Maybe.h"
#include "mozilla/WritingModes.h"
#include "nsDirection.h"
@@ -2047,15 +2048,14 @@ public:
virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0;
/**
* Get the intrinsic ratio of this element, or nsSize(0,0) if it has
* no intrinsic ratio. The intrinsic ratio is the ratio of the
* height/width of a box with an intrinsic size or the intrinsic
* aspect ratio of a scalable vector image without an intrinsic size.
* Get the intrinsic ratio of this element, or a default-constructed
* AspectRatio if it has no intrinsic ratio.
*
* Either one of the sides may be zero, indicating a zero or infinite
* ratio.
* The intrinsic ratio is the ratio of the width/height of a box with an
* intrinsic size or the intrinsic aspect ratio of a scalable vector image
* without an intrinsic size.
*/
virtual nsSize GetIntrinsicRatio() = 0;
virtual mozilla::AspectRatio GetIntrinsicRatio() = 0;
/**
* Bit-flags to pass to ComputeSize in |aFlags| parameter.
Loaded 100 of 141 files, more files were not shown because too many files have changed in this diff. Show more