Compare commits
59
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a6f632714f | ||
|
|
b28effe2ea | ||
|
|
afd6edd667 | ||
|
|
582a1ce72a | ||
|
|
71ac56ba40 | ||
|
|
ae184d09e6 | ||
|
|
868f0755ae | ||
|
|
5ca8fbd41c | ||
|
|
549c8b9283 | ||
|
|
77e8ba7eaf | ||
|
|
e854d58633 | ||
|
|
d58cb8e11b | ||
|
|
429a7bdb93 | ||
|
|
3f14e9ec5f | ||
|
|
aefb293793 | ||
|
|
c583315558 | ||
|
|
834ecdc59a | ||
|
|
798c2ed4f8 | ||
|
|
767b637c83 | ||
|
|
702ad218b0 | ||
|
|
b9af9c0c51 | ||
|
|
9d6e28d3d0 | ||
|
|
c735355ae1 | ||
|
|
10a10fd375 | ||
|
|
1012dbe9e5 | ||
|
|
9982c1f5cb | ||
|
|
fe912e94e4 | ||
|
|
770b1c9071 | ||
|
|
daf56131a7 | ||
|
|
d8686de401 | ||
|
|
c8a38346c8 | ||
|
|
70bafe4df5 | ||
|
|
498b1ab0c8 | ||
|
|
2f145b6eda | ||
|
|
06a092d08e | ||
|
|
d107016d37 | ||
|
|
63371593c0 | ||
|
|
ce1dc7e6c6 | ||
|
|
a4780ebaeb | ||
|
|
c384fa6e25 | ||
|
|
5e8e0d05a6 | ||
|
|
bf95a03189 | ||
|
|
c75e412f17 | ||
|
|
0bbe6ec105 | ||
|
|
48d31ea5eb | ||
|
|
3cf0843679 | ||
|
|
ff21776616 | ||
|
|
2f022ab1fa | ||
|
|
14e7f881be | ||
|
|
4f03fb2798 | ||
|
|
3dd316f739 | ||
|
|
972ab6d437 | ||
|
|
83ae5bd019 | ||
|
|
c237a54f23 | ||
|
|
8f72a673ca | ||
|
|
3266e0976f | ||
|
|
4433519ae8 | ||
|
|
d419fe2d52 | ||
|
|
c77c6de9ce |
No files matched your search
@@ -23,4 +23,3 @@
|
||||
# don't change CLOBBER for WebIDL changes any more.
|
||||
|
||||
Clobber for NSS update
|
||||
|
||||
@@ -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
File diff suppressed because it is too large.
Load diff
+1205
-888
File diff suppressed because it is too large.
Load diff
@@ -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
@@ -14,7 +14,7 @@ EXPORTS.mozilla.dom += [
|
||||
'AbortSignal.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
SOURCES += [
|
||||
'AbortController.cpp',
|
||||
'AbortSignal.cpp',
|
||||
]
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -2872,6 +2872,8 @@ public:
|
||||
virtual void ScheduleIntersectionObserverNotification() = 0;
|
||||
virtual void NotifyIntersectionObservers() = 0;
|
||||
|
||||
bool ModuleScriptsEnabled();
|
||||
|
||||
protected:
|
||||
bool GetUseCounter(mozilla::UseCounter aUseCounter)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,8 @@ protected:
|
||||
nsAString& aType,
|
||||
nsAString& aMedia,
|
||||
bool* aIsScoped,
|
||||
bool* aIsAlternate) = 0;
|
||||
bool* aIsAlternate,
|
||||
bool* aIsExplicitlyEnabled) = 0;
|
||||
|
||||
virtual mozilla::CORSMode GetCORSMode() const
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,6 +206,11 @@ public:
|
||||
return GetReferrerPolicyAsEnum();
|
||||
}
|
||||
|
||||
bool IsAwaitingLoad() const
|
||||
{
|
||||
return !!mPendingImageLoadTask;
|
||||
}
|
||||
|
||||
int32_t X();
|
||||
int32_t Y();
|
||||
// Uses XPCOM GetLowsrc.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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']
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
+379
-313
File diff suppressed because it is too large.
Load diff
+66
-23
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ SVGScriptElement::GetScriptCharset(nsAString& charset)
|
||||
}
|
||||
|
||||
void
|
||||
SVGScriptElement::FreezeUriAsyncDefer()
|
||||
SVGScriptElement::FreezeExecutionAttrs(nsIDocument* aOwnerDoc)
|
||||
{
|
||||
if (mFrozen) {
|
||||
return;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -95,7 +95,8 @@ protected:
|
||||
nsAString& aType,
|
||||
nsAString& aMedia,
|
||||
bool* aIsScoped,
|
||||
bool* aIsAlternate) override;
|
||||
bool* aIsAlternate,
|
||||
bool* aIsExplicitlyEnabled) override;
|
||||
virtual CORSMode GetCORSMode() const override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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 \
|
||||
|
||||
@@ -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
@@ -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) ===
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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().
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -109,6 +109,7 @@ EXPORTS += [
|
||||
]
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'AspectRatio.h',
|
||||
'CSSAlignUtils.h',
|
||||
'ReflowInput.h',
|
||||
'ReflowOutput.h',
|
||||
|
||||
@@ -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
@@ -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)) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in new issue
Block a user