Compare commits

...
Author SHA1 Message Date
Moonchild a9b7af2c28 [layout] Prevent recursion of callbacks in PressShell. 2026-08-21 21:18:20 +02:00
Moonchild 501212e324 [gfx] Clean up cairo-win32-printing-surface.c
- Reformat code for readability.
- Check allocations in _cairo_win32_printing_surface_paint_linear_pattern.
2026-08-21 15:46:36 +02:00
Moonchild 7158edf5c8 [gfx fonts] Check format 4 subtable length and Zero newly-allocated range. 2026-08-20 15:45:42 +02:00
Moonchild fcc96573dd [gfx] Add buffer integer limit check to NVImage::GetAsSourceSurface. 2026-08-20 15:13:25 +02:00
Moonchild 79c57f2dab Merge pull request 'Restore the ability to compile on MIPS targets' (#3166) from Basilisk-Dev/UXP-contrib:mips-fix into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3166
2026-08-19 15:31:24 +00:00
Moonchild ed63bc8a89 [gfx] Hold a strong ref to platform font entry. 2026-08-19 15:24:35 +02:00
Moonchild 1de3a27f36 [DOM] Keep resized windows within reasonable bounds.
The size is now clamped to twice the available area of the screen the
window is on. Twice rather than exactly the screen, because the size we
get for a screen is not always accurate, on Wayland in particular... (¬_¬)
2026-08-19 11:18:02 +02:00
Moonchild e9d47c2c07 Merge pull request 'K.I.S.S.: Spot-fix jsprf for OS X 10.5 and 10.6' (#3164) from strnlen-kiss into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3164
2026-08-19 08:36:02 +00:00
Basilisk-Dev 1ba68a43cd Issue #3062 - Fix sspidermonkey and JIT issues when compiling on MIPS 2026-08-18 10:24:05 -04:00
Basilisk-Dev e60dbff022 Issue #3062 - Fix GNU assembler issues in libvpx on MIPS 2026-08-18 10:24:05 -04:00
Basilisk-Dev b3aad357ab Issue #3062 - Fix MIPS compilation in ffvpx 2026-08-18 10:24:00 -04:00
Moonchild 4c346cc711 Replace strnlen with memchr. See code comment. 2026-08-15 10:22:56 +02:00
Moonchild ca36b1f452 Merge pull request 'Implement support for adoptedStyleSheets' (#3161) from Basilisk-Dev/UXP-contrib:adoptedstylesheets into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3161
2026-08-13 13:05:05 +00:00
Basilisk-Dev 27195b1e7a Issue #3157 - Implement support for adoptedStyleSheets 2026-08-12 08:58:52 -04:00
Moonchild 948559c22c Revert "[parser] Restrict subtree root check to DOM image elements only."
As it turns out, the reported regression was actually noncompliant HTML
and the initial implementation was correct.

This reverts commit fc25f50e5f.
2026-08-11 17:39:55 +02:00
Moonchild 5d7a1ca5a9 Merge pull request 'Several Python 3-related fixes to the build system' (#3160) from FranklinDM/UXP-contrib:work_python3-fixes-build1 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3160
2026-08-10 12:40:05 +00:00
Francis Dominic Fajardo 613443c5eb No issue - Remove old Python 2 workaround that encodes environment vars in bytes
This should fix installer packaging.
2026-08-10 19:10:18 +08:00
Basilisk-Dev d7884bb96c No issue - Fix faster build packaging on Python 3 2026-08-10 19:10:11 +08:00
Moonchild fc25f50e5f [parser] Restrict subtree root check to DOM image elements only.
This was too broadly applied, resulting in named form elements not being
accessible through the DOM tree if not in the same subtree root.
2026-08-09 18:50:50 +02:00
Moonchild b70b3a5aa1 Merge pull request 'Clean up NSIS scripting.' (#3121) from nsis-cleanup into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3121
2026-08-06 13:50:39 +00:00
Moonchild 88ae39ed04 Merge pull request 'Implement :has() CSS pseudo class' (#3152) from Basilisk-Dev/UXP-contrib:css-has into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3152
2026-08-06 06:34:14 +00:00
Basilisk-Dev d893526f82 Issue #2473 - Inline functions in CSS :has() implementation 2026-07-29 16:48:12 -04:00
Moonchild 4d5b1cc5d8 Merge branch 'nss-3.125-port' 2026-07-28 10:50:50 +02:00
Moonchild 0e521f6302 Bump NSS (UXP) patch level. 2026-07-28 10:10:27 +02:00
Moonchild 9cacfcff57 Merge remote-tracking branch 'dbsoft/flex-button-fix2' 2026-07-28 10:08:00 +02:00
John Schanck 21ad7adc90 Bug 2043887 - guard against integer overflow in CERT_Hexify. 2026-07-28 10:03:44 +02:00
Benjamin Beurdouche 9a29430751 Bug 2027353 - clamp input.len to testString size in pk11_mergeSecretKey. 2026-07-28 09:59:51 +02:00
Benjamin Beurdouche 481d4868b0 Bug 2029433 - Bounds-check wrap index in PK11_GetWrapKey to match PK11_SetWrapKey. 2026-07-28 09:57:10 +02:00
Anna Weine d148c11717 Bug 2028954 - CERT_DecodeAVAValue — Integer Overflow in Output Buffer Sizing. 2026-07-28 09:53:26 +02:00
Moonchild bc322e58f8 Bug 2027364 - Set tail pointer to null in static slot lists when deallocating. 2026-07-28 09:22:56 +02:00
John Schanck e48a6f26a5 Bug 2032110 - fix two integer overflows on LLP64 systems. 2026-07-27 23:58:14 +02:00
John Schanck d85edd01df Bug 2030102 - avoid leaving a dangling ss->sec.ci.sid on allocation failure. 2026-07-27 23:49:55 +02:00
Maurice Dauer 296379d751 Bug 2027325 - Reject empty nickname in PK11_TraverseCertsForNicknameInSlot. 2026-07-27 23:46:32 +02:00
Moonchild 7ba9fc2801 Bug 2030563 - Validate CKA_CERTIFICATE_TYPE ulValueLen in nss_cert_type_from_ck_attrib. 2026-07-27 23:22:58 +02:00
Brian Smith a9ac8b390f Issue #3153 - Make sure buttons report a definite size for flex containers.
Second try, this time ONLY do it for flex container or grids.
This should prevent layout problems in non-flex scenarios.
2026-07-27 12:36:24 -05:00
Benjamin Beurdouche 71c0f8246c Bug 2029807 - Guard padding read against empty output in SEC_PKCS7DecryptContents. 2026-07-27 19:12:42 +02:00
Benjamin Beurdouche 6cda35442f Bug 2027346 - validate encoded EC params length and tag in SECKEY_ECParamsToKeySize/BasePointOrderLen. 2026-07-27 19:05:33 +02:00
Benjamin Beurdouche 1dba423327 Bug 2027371 - rewrite labelLen bound in tls13_HkdfExpandLabelGeneral to avoid unsigned overflow. 2026-07-27 18:56:08 +02:00
Benjamin Beurdouche e2af0b28bf Bug 2027373 - guard space subtraction in ssl_CallCustomExtensionSenders. 2026-07-27 18:51:32 +02:00
Benjamin Beurdouche 5ea9b7b80a Bug 2029901 - Guard against keySize overflow in IKE PRF/PRF+ output sizing. 2026-07-27 18:44:55 +02:00
Benjamin Beurdouche b799e100ad Bug 2027362 - bound usageCount in PK11_UnwrapPrivKey to keyTemplate capacity. 2026-07-27 18:39:10 +02:00
Benjamin Beurdouche 1c500a6abb Bug 2027349 - reject empty nickname in PK11_TraverseCertsForNicknameInSlot. 2026-07-27 18:27:47 +02:00
Moonchild b909fccc92 Revert "Issue #3153 - Make sure buttons report a definite size for flex containers."
This reverts commit 3e223cbfb4.
2026-07-27 17:59:43 +02:00
Moonchild abddee43b4 Merge remote-tracking branch 'dbsoft/flex-button-fix' 2026-07-27 14:41:27 +02:00
Moonchild 49d184e550 [network] Fix CacheEntry::mDoomCallback data race. 2026-07-27 14:32:51 +02:00
Brian Smith 3e223cbfb4 Issue #3153 - Make sure buttons report a definite size for flex containers. 2026-07-27 05:38:09 -05:00
Basilisk-Dev 7341809f67 Issue #2473 - implement :has() CSS pseudo class 2026-07-26 14:35:40 -04:00
Moonchild dd9099a7d3 [layout] Fix nsFrameSetFrame primary frame handling of replicated children. 2026-07-26 19:55:49 +02:00
Moonchild 31558a1521 Merge pull request 'Issue #3061 Follow-up: Remove network tickler prefs' (#3151) from Shadow/UXP-contrib:contrib into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3151
2026-07-26 15:45:08 +00:00
Shadow 0e683bf699 Issue #3061 Follow-up: Remove network tickler prefs 2026-07-26 15:39:39 +00:00
Moonchild 6459dec5bb [DOM media] Perform more thorough checks on video regions. 2026-07-26 15:04:18 +02:00
az 0e930fba3f Bug 2045742 2026-07-26 10:08:13 +02:00
Moonchild 3b683bbe59 Merge pull request 'Align aspect-ratio to spec' (#3150) from Basilisk-Dev/UXP-contrib:css-aspect-ratio into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3150
2026-07-26 07:06:00 +00:00
Basilisk-Dev 0042e54c38 Issue #2404 - Split aspect ratio enum types into a separate header to fix compilation issues 2026-07-25 12:24:15 -04:00
Andrew McCreight e75201f7d1 Bug 2049523 - Make ToJSValue for float consistent with double. 2026-07-25 17:04:14 +02:00
Moonchild 28c47723b2 Fix comment (nit) 2026-07-25 16:12:08 +02:00
Randell Jesup 3d872ff7b0 Bug 2029734: Flush before calling sctp_process_init() 2026-07-25 14:52:29 +02:00
Moonchild beb684c29e No issue - Use strnlen instead of strnlen_s.
Apparently, GCC doesn't like the _s variants.
2026-07-25 13:08:15 +02:00
Moonchild 775588b75d [image] Make sure the image was fully and cleanly decoded before finalizing its animation state as complete. 2026-07-25 10:01:55 +02:00
Basilisk-Dev 8a2a5d837c Issue #2404 - Fix aspect ratio sizing for grid items 2026-07-25 00:58:20 -04:00
Basilisk-Dev 8add755c81 Issue #2404 - Improvements to CSS aspect-ratio spec compliance 2026-07-25 00:57:58 -04:00
Moonchild 257c64567e [parser] Associate image elements with form only if the form and the intended parent are in the same tree. 2026-07-24 21:12:04 +02:00
Moonchild d0b61d4a68 No issue - CallUpdateWindow is [[nodiscard]], but we don't need to use
the result here.
2026-07-24 19:29:00 +02:00
Moonchild 3b5f50cc35 Merge pull request 'No Issue - Remove the half-life experiment in HTTP cache' (#3149) from Shadow/UXP-contrib:master into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3149
2026-07-24 14:32:21 +00:00
Moonchild 27c6a7f477 [DOM media] Stop accepting audio samples with too low sample rates.
This sets the floor to 8kHz audio, which is generally considered to be
the lowest acceptable "phone quality"/"walkie-talkie" audio rate.
Audio outside the range will refuse to decode after this commit and give
a console error.
This avoids a whole class of potential bugs.
2026-07-24 14:52:40 +02:00
Moonchild c65f84214e [layout] Add corner-case correctness check in DottedCornerFinder::FindBestOverlap. 2026-07-24 13:17:54 +02:00
Moonchild a317c65fd7 [network] Add usrsctp TSN gap check. 2026-07-24 12:58:20 +02:00
Shadow 0ec35ce534 No Issue - Remove the half-life experiment in HTTP cache
Reviewed-on: https://repo.palemoon.org/Shadow/UXP-contrib/pulls/1
2026-07-24 09:49:48 +00:00
Moonchild bf0c040722 [js] Clamp length of regexp captures array for dollar substitution. 2026-07-22 22:37:50 +02:00
Moonchild ebadd51401 [js] Initialize BaselineFrame return value slot in OnLeaveBaselineFrame. 2026-07-22 20:26:07 +02:00
Moonchild 5ed0bf8b44 [DOM] Make parser update form owner properly 2026-07-22 17:12:32 +02:00
Moonchild f877c1dba5 [gfx] Hold a strong ref during GetFontAt lookup. 2026-07-22 10:27:53 +02:00
Moonchild 4c14f8f89b [gfx] Add bounds checks and limit reverse scanning of ligature data. 2026-07-22 09:43:54 +02:00
Moonchild c119728965 Merge pull request 'Implement CSSStyleSheet replaceSync' (#3145) from Basilisk-Dev/UXP-contrib:replacesync into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3145
2026-07-22 06:02:21 +00:00
Moonchild fa55b9c2e8 [js] Guard against OOB string sizes in internal Printf 2026-07-22 01:39:03 +02:00
Basilisk-Dev 16aba76fc5 Issue #3144 - Implement CSSStyleSheet replaceSync 2026-07-21 04:23:19 -04:00
Moonchild 995def99cd No issue - Exclude some files from the preprocessor that don't have directives in them. 2026-07-19 15:57:10 +02:00
Moonchild 923e52789c Merge pull request 'Convert std::*<T>::value/::type to _v and _t suffixes.' (#3143) from 1803 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3143
2026-07-19 07:40:35 +00:00
Moonchild 22d945430b Issue #3061 - Remove network tickler.
Resolves #3061
2026-07-19 08:17:05 +02:00
Moonchild 21743e0b7c Issue #3120 - Clean up NSIS scripting.
Removes Quicklaunch shortcut code, UAC guards (always supported on target
OSes) and LSP guards (ditto).

Resolves #3120
2026-06-13 12:19:53 +02:00
135 changed files with 3107 additions and 1729 deletions

No files matched your search

+1 -1
View File
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for Idle GC backout
Clobber for removal of network tickler
+1 -1
View File
@@ -81,7 +81,7 @@ $(addprefix install-,$(INSTALL_MANIFESTS)): install-%: $(addprefix $(TOPOBJDIR)/
--track install_$(subst /,_,$*).track \
$(TOPOBJDIR)/$* \
-DAB_CD=en-US \
-DBOOKMARKS_INCLUDE_DIR=$(TOPSRCDIR)/browser/locales/en-US/profile \
-DBOOKMARKS_INCLUDE_DIR=$(TOPSRCDIR)/$(MOZ_BUILD_APP)/locales/en-US/profile \
$(ACDEFINES) \
install_$(subst /,_,$*)
+1 -1
View File
@@ -3,6 +3,6 @@
# 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/.
JS_PREFERENCE_PP_FILES += [
JS_PREFERENCE_FILES += [
'devtools.js',
]
+99
View File
@@ -5,13 +5,19 @@
#include "DocumentOrShadowRoot.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/CSSStyleSheetBinding.h"
#include "mozilla/dom/StyleSheetList.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsDocument.h"
#include "nsFocusManager.h"
#include "ShadowRoot.h"
#include "XULDocument.h"
#include "nsLayoutUtils.h"
#include "nsSVGUtils.h"
#include "jsapi.h"
class nsINode;
class nsIDocument;
@@ -43,6 +49,99 @@ DocumentOrShadowRoot::EnsureDOMStyleSheets()
return *mDOMStyleSheets;
}
void
DocumentOrShadowRoot::GetAdoptedStyleSheets(
JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
ErrorResult& aRv) const
{
JS::Rooted<JS::Value> value(aCx);
if (!ToJSValue(aCx, mAdoptedStyleSheets, &value)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
MOZ_ASSERT(value.isObject());
aResult.set(&value.toObject());
}
void
DocumentOrShadowRoot::SetAdoptedStyleSheets(
JSContext* aCx,
JS::Handle<JSObject*> aSheets,
ErrorResult& aRv)
{
bool isArray = false;
if (!JS_IsArrayObject(aCx, aSheets, &isArray)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!isArray) {
aRv.ThrowTypeError<MSG_NOT_SEQUENCE>(
NS_LITERAL_STRING("DocumentOrShadowRoot.adoptedStyleSheets"));
return;
}
uint32_t length = 0;
if (!JS_GetArrayLength(aCx, aSheets, &length)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
nsIDocument* document = AsNode().OwnerDoc();
nsTArray<RefPtr<CSSStyleSheet>> newSheets;
if (!newSheets.SetCapacity(length, fallible)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
JS::Rooted<JS::Value> value(aCx);
for (uint32_t i = 0; i < length; ++i) {
if (!JS_GetElement(aCx, aSheets, i, &value)) {
aRv.Throw(NS_ERROR_FAILURE);
return;
}
if (!value.isObject()) {
aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(
NS_LITERAL_STRING("Element of DocumentOrShadowRoot.adoptedStyleSheets"),
NS_LITERAL_STRING("CSSStyleSheet"));
return;
}
RefPtr<CSSStyleSheet> sheet;
nsresult rv = UnwrapObject<prototypes::id::CSSStyleSheet,
CSSStyleSheet>(&value.toObject(), sheet);
if (NS_FAILED(rv)) {
aRv.ThrowTypeError<MSG_DOES_NOT_IMPLEMENT_INTERFACE>(
NS_LITERAL_STRING("Element of DocumentOrShadowRoot.adoptedStyleSheets"),
NS_LITERAL_STRING("CSSStyleSheet"));
return;
}
if (!sheet->IsConstructed() || sheet->ConstructorDocument() != document) {
aRv.Throw(NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
newSheets.AppendElement(sheet);
}
nsTArray<RefPtr<CSSStyleSheet>> oldSheets;
oldSheets.SwapElements(mAdoptedStyleSheets);
mAdoptedStyleSheets.SwapElements(newSheets);
if (mKind == Kind::Document) {
static_cast<nsDocument&>(AsNode()).AdoptedStyleSheetsChanged(oldSheets,
mAdoptedStyleSheets);
return;
}
static_cast<ShadowRoot&>(AsNode()).AdoptedStyleSheetsChanged(oldSheets,
mAdoptedStyleSheets);
}
Element*
DocumentOrShadowRoot::GetElementById(const nsAString& aElementId)
{
+16
View File
@@ -11,11 +11,14 @@
#include "nsContentListDeclarations.h"
#include "nsNameSpaceManager.h"
#include "mozilla/dom/NameSpaceConstants.h"
#include "js/RootingAPI.h"
class nsContentList;
class nsINode;
namespace mozilla {
class CSSStyleSheet;
class ErrorResult;
class StyleSheet;
namespace dom {
@@ -83,6 +86,18 @@ public:
StyleSheetList& EnsureDOMStyleSheets();
void GetAdoptedStyleSheets(JSContext* aCx,
JS::MutableHandle<JSObject*> aResult,
mozilla::ErrorResult& aRv) const;
void SetAdoptedStyleSheets(JSContext* aCx,
JS::Handle<JSObject*> aSheets,
mozilla::ErrorResult& aRv);
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& AdoptedStyleSheets() const
{
return mAdoptedStyleSheets;
}
Element* GetElementById(const nsAString& aElementId);
/**
@@ -151,6 +166,7 @@ protected:
Element* GetRetargetedFocusedElement();
nsTArray<RefPtr<mozilla::StyleSheet>> mStyleSheets;
nsTArray<RefPtr<mozilla::CSSStyleSheet>> mAdoptedStyleSheets;
RefPtr<mozilla::dom::StyleSheetList> mDOMStyleSheets;
/*
+53 -4
View File
@@ -18,6 +18,7 @@
#include "mozilla/dom/StyleSheetList.h"
#include "nsXBLPrototypeBinding.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
@@ -30,6 +31,7 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(ShadowRoot)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ShadowRoot,
DocumentFragment)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdoptedStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAssociatedBinding)
for (auto iter = tmp->mIdentifierMap.ConstIter(); !iter.Done();
iter.Next()) {
@@ -42,6 +44,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ShadowRoot)
tmp->GetHost()->RemoveMutationObserver(tmp);
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
for (CSSStyleSheet* sheet : tmp->mAdoptedStyleSheets) {
sheet->RemoveAdopter(tmp);
}
tmp->mAdoptedStyleSheets.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAssociatedBinding)
tmp->mIdentifierMap.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(DocumentFragment)
@@ -90,6 +96,11 @@ ShadowRoot::~ShadowRoot()
host->RemoveMutationObserver(this);
}
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
sheet->RemoveAdopter(this);
}
mAdoptedStyleSheets.Clear();
UnsetFlags(NODE_IS_IN_SHADOW_TREE);
// nsINode destructor expects mSubtreeRoot == this.
@@ -270,15 +281,20 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
linkingElement->SetStyleSheet(aSheet); // This sets the ownerNode on the sheet
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() == DocumentOrShadowRoot::SheetCount());
MOZ_DIAGNOSTIC_ASSERT(mProtoBinding->SheetCount() ==
DocumentOrShadowRoot::SheetCount() +
mAdoptedStyleSheets.Length());
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
// FIXME(emilio, bug 1425759): For now we keep them duplicated, the proto
// binding will disappear soon (tm).
// FIXME(emilio, bug 1425759): For now we keep regular sheets duplicated;
// adopted sheets are stored as a suffix on the proto binding only.
{
size_t i = 0;
for (RefPtr<StyleSheet>& sheet : mStyleSheets) {
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
}
for (RefPtr<CSSStyleSheet>& sheet : mAdoptedStyleSheets) {
MOZ_DIAGNOSTIC_ASSERT(sheet.get() == mProtoBinding->StyleSheetAt(i++));
}
}
#endif
@@ -287,7 +303,7 @@ ShadowRoot::InsertSheet(StyleSheet* aSheet,
for (size_t i = 0; i <= SheetCount(); i++) {
if (i == SheetCount()) {
AppendStyleSheet(*aSheet);
mProtoBinding->AppendStyleSheet(aSheet);
mProtoBinding->InsertStyleSheetAt(i, aSheet);
break;
}
@@ -322,6 +338,39 @@ ShadowRoot::RemoveSheet(StyleSheet* aSheet)
}
}
void
ShadowRoot::AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
{
OwnerDoc()->BeginUpdate(UPDATE_STYLE);
bool applicableChange = false;
for (size_t i = 0; i < aOldSheets.Length(); ++i) {
CSSStyleSheet* sheet = aOldSheets[i];
if (aOldSheets.IndexOf(sheet) == i) {
mProtoBinding->RemoveStyleSheet(sheet);
}
applicableChange = applicableChange || sheet->IsApplicable();
sheet->RemoveAdopter(this);
}
for (size_t i = 0; i < aNewSheets.Length(); ++i) {
CSSStyleSheet* sheet = aNewSheets[i];
sheet->AddAdopter(this);
if (aNewSheets.IndexOf(sheet) == i) {
mProtoBinding->AppendStyleSheet(sheet);
}
applicableChange = applicableChange || sheet->IsApplicable();
}
if (applicableChange) {
StyleSheetChanged();
}
OwnerDoc()->EndUpdate(UPDATE_STYLE);
}
void
ShadowRoot::AddToIdTable(Element* aElement, nsIAtom* aId)
{
+4 -1
View File
@@ -21,6 +21,7 @@ class nsXBLPrototypeBinding;
namespace mozilla {
class CSSStyleSheet;
class EventChainPreVisitor;
namespace dom {
@@ -59,6 +60,9 @@ public:
// [deprecated] Shadow DOM v0
void InsertSheet(StyleSheet* aSheet, nsIContent* aLinkingContent);
void RemoveSheet(StyleSheet* aSheet);
void AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets);
StyleSheetList* StyleSheets()
{
return &DocumentOrShadowRoot::EnsureDOMStyleSheets();
@@ -173,4 +177,3 @@ protected:
} // namespace mozilla
#endif // mozilla_dom_shadowroot_h__
+60
View File
@@ -13,6 +13,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/AutoRestore.h"
#include "mozilla/BinarySearch.h"
#include "mozilla/CSSStyleSheet.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/EffectSet.h"
#include "mozilla/IntegerRange.h"
@@ -1402,6 +1403,10 @@ nsDocument::~nsDocument()
for (StyleSheet* sheet : mStyleSheets) {
sheet->ClearAssociatedDocument();
}
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
sheet->RemoveAdopter(this);
}
mAdoptedStyleSheets.Clear();
for (auto& sheets : mAdditionalSheets) {
for (StyleSheet* sheet : sheets) {
sheet->ClearAssociatedDocument();
@@ -1635,6 +1640,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
// Traverse all our nsCOMArrays.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAdoptedStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
@@ -1740,6 +1746,11 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
for (CSSStyleSheet* sheet : tmp->mAdoptedStyleSheets) {
sheet->RemoveAdopter(tmp);
}
tmp->mAdoptedStyleSheets.Clear();
if (tmp->mStyleSheetSetList) {
tmp->mStyleSheetSetList->Disconnect();
tmp->mStyleSheetSetList = nullptr;
@@ -2205,6 +2216,12 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
SheetType::Doc);
for (CSSStyleSheet* sheet : mAdoptedStyleSheets) {
if (sheet->IsApplicable()) {
aStyleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
}
mStyleSetFilled = true;
}
@@ -3872,6 +3889,37 @@ nsDocument::RemoveStyleSheetFromStyleSets(StyleSheet* aSheet)
}
}
void
nsDocument::AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
{
BeginUpdate(UPDATE_STYLE);
nsCOMPtr<nsIPresShell> shell = GetShell();
nsStyleSet* styleSet = shell ? shell->StyleSet() : nullptr;
for (size_t i = 0; i < aOldSheets.Length(); ++i) {
CSSStyleSheet* sheet = aOldSheets[i];
if (styleSet && sheet->IsApplicable() &&
aOldSheets.IndexOf(sheet) == i) {
styleSet->RemoveStyleSheet(SheetType::Doc, sheet);
}
sheet->RemoveAdopter(this);
}
for (size_t i = 0; i < aNewSheets.Length(); ++i) {
CSSStyleSheet* sheet = aNewSheets[i];
sheet->AddAdopter(this);
if (styleSet && sheet->IsApplicable() &&
aNewSheets.IndexOf(sheet) == i) {
styleSet->AppendStyleSheet(SheetType::Doc, sheet);
}
}
EndUpdate(UPDATE_STYLE);
}
void
nsDocument::RemoveStyleSheet(StyleSheet* aSheet)
{
@@ -3961,6 +4009,18 @@ nsDocument::SetStyleSheetApplicableState(StyleSheet* aSheet,
} else {
RemoveStyleSheetFromStyleSets(aSheet);
}
} else if (mAdoptedStyleSheets.IndexOf(aSheet->AsConcrete()) !=
mAdoptedStyleSheets.NoIndex) {
nsCOMPtr<nsIPresShell> shell = GetShell();
if (shell) {
if (aApplicable) {
shell->StyleSet()->AppendStyleSheet(SheetType::Doc,
aSheet->AsConcrete());
} else {
shell->StyleSet()->RemoveStyleSheet(SheetType::Doc,
aSheet->AsConcrete());
}
}
}
// We have to always notify, since this will be called for sheets
+4
View File
@@ -95,6 +95,7 @@ class nsISecurityConsoleMessage;
class nsPIBoxObject;
namespace mozilla {
class CSSStyleSheet;
class EventChainPreVisitor;
namespace dom {
class BoxObject;
@@ -471,6 +472,9 @@ public:
nsTArray<RefPtr<mozilla::StyleSheet>>& aNewSheets) override;
virtual void AddStyleSheetToStyleSets(mozilla::StyleSheet* aSheet);
virtual void RemoveStyleSheetFromStyleSets(mozilla::StyleSheet* aSheet);
void AdoptedStyleSheetsChanged(
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aOldSheets,
const nsTArray<RefPtr<mozilla::CSSStyleSheet>>& aNewSheets);
virtual void InsertStyleSheetAt(mozilla::StyleSheet* aSheet,
size_t aIndex) override;
+1
View File
@@ -444,6 +444,7 @@ GK_ATOM(handheldFriendly, "HandheldFriendly")
GK_ATOM(handler, "handler")
GK_ATOM(handlers, "handlers")
GK_ATOM(HARD, "HARD")
GK_ATOM(hasSelectorDependency, "has-selector-dependency")
GK_ATOM(hasSameNode, "has-same-node")
GK_ATOM(hbox, "hbox")
GK_ATOM(head, "head")
+19 -3
View File
@@ -6162,7 +6162,6 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight, b
// This one is easy. Just ensure the variable is greater than 100;
if ((aWidth && *aWidth < 100) || (aHeight && *aHeight < 100)) {
// Check security state for use in determing window dimensions
if (!nsContentUtils::IsCallerChrome()) {
//sec check failed
if (aWidth && *aWidth < 100) {
@@ -6173,6 +6172,21 @@ nsGlobalWindow::CheckSecurityWidthAndHeight(int32_t* aWidth, int32_t* aHeight, b
}
}
}
// Check for the screen dimensions and keep the size in the range of the
// screen size the window is on. We allow twice the screen size because the
// size we get for a screen is not always accurate, on Wayland in particular,
// and all we need is to keep the size in a reasonable range.
nsCOMPtr<nsIDOMScreen> screen = GetScreen();
int32_t screenWidth, screenHeight;
screen->GetAvailWidth(&screenWidth);
screen->GetAvailHeight(&screenHeight);
if (aWidth && *aWidth > 2 * screenWidth) {
*aWidth = 2 * screenWidth;
}
if (aHeight && *aHeight > 2 * screenHeight) {
*aHeight = 2 * screenHeight;
}
}
// NOTE: Arguments to this function should have values in device pixels
@@ -8091,8 +8105,10 @@ nsGlobalWindow::ResizeByOuter(int32_t aWidthDif, int32_t aHeightDif,
nsIntSize cssSize(DevToCSSIntPixels(nsIntSize(width, height)));
cssSize.width += aWidthDif;
cssSize.height += aHeightDif;
// The deltas come from content and can be large enough to overflow a 32-bit
// add, so do the arithmetic in 64 bits and keep the result in range.
cssSize.width = int32_t(std::clamp<int64_t>(int64_t(cssSize.width) + aWidthDif, 0, INT32_MAX));
cssSize.height = int32_t(std::clamp<int64_t>(int64_t(cssSize.height) + aHeightDif, 0, INT32_MAX));
CheckSecurityWidthAndHeight(&cssSize.width, &cssSize.height, aCallerIsChrome);
+3
View File
@@ -46,6 +46,9 @@ nsIDocument::FindDocStyleSheetInsertionPoint(
break;
}
}
if (sheet->IsConstructed()) {
break;
}
if (sheet == GetFirstAdditionalAuthorSheet()) {
break;
}
+2 -2
View File
@@ -97,7 +97,7 @@ ToJSValue(JSContext* aCx,
return true;
}
// accept floating point types
// Accept floating point types
inline bool
ToJSValue(JSContext* aCx,
float aArgument,
@@ -106,7 +106,7 @@ ToJSValue(JSContext* aCx,
// Make sure we're called in a compartment
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
aValue.setNumber(aArgument);
aValue.set(JS_NumberValue(double(aArgument)));
return true;
}
+2 -10
View File
@@ -876,20 +876,12 @@ HTMLImageElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return HTMLImageElementBinding::Wrap(aCx, this, aGivenProto);
}
#ifdef DEBUG
nsIDOMHTMLFormElement*
HTMLImageElement::GetForm() const
{
return mForm;
}
#endif
void
HTMLImageElement::SetForm(nsIDOMHTMLFormElement* aForm)
{
NS_PRECONDITION(aForm, "Don't pass null here");
NS_ASSERTION(!mForm,
"We don't support switching from one non-null form to another.");
MOZ_ASSERT(!mForm && !HasFlag(ADDED_TO_FORM),
"We don't support switching from one non-null form to another.");
mForm = static_cast<HTMLFormElement*>(aForm);
}
+2 -3
View File
@@ -216,9 +216,8 @@ public:
SetHTMLAttr(nsGkAtoms::lowsrc, aLowsrc, aError);
}
#ifdef DEBUG
nsIDOMHTMLFormElement* GetForm() const;
#endif
HTMLFormElement* GetForm() const { return mForm; };
void SetForm(nsIDOMHTMLFormElement* aForm);
void ClearForm(bool aRemoveFromForm);
+11 -4
View File
@@ -1487,8 +1487,15 @@ nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttr
}
if (w && h && *w != 0 && *h != 0) {
nsCSSValue* aspect_ratio = aData->ValueForAspectRatio();
aspect_ratio->SetFloatValue((float(*w) / float(*h)), eCSSUnit_Number);
nsCSSValue width;
width.SetFloatValue(float(*w), eCSSUnit_Number);
nsCSSValue height;
height.SetFloatValue(float(*h), eCSSUnit_Number);
nsCSSValue ratio;
ratio.SetPairValue(width, height);
nsCSSValue autoValue;
autoValue.SetAutoValue();
aData->ValueForAspectRatio()->SetPairValue(autoValue, ratio);
}
}
}
@@ -1824,8 +1831,8 @@ void
nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
{
NS_PRECONDITION(aForm, "Don't pass null here");
NS_ASSERTION(!mForm,
"We don't support switching from one non-null form to another.");
MOZ_ASSERT(!mForm && !HasFlag(ADDED_TO_FORM),
"We don't support switching from one non-null form to another.");
// keep a *weak* ref to the form here
mForm = static_cast<HTMLFormElement*>(aForm);
+1 -1
View File
@@ -2455,7 +2455,7 @@ ContentChild::RecvUpdateWindow(const uintptr_t& aChildId)
if (parentInstance) {
// sync! update call to the plugin instance that forces the
// plugin to paint its child window.
parentInstance->CallUpdateWindow();
Unused << parentInstance->CallUpdateWindow();
}
return true;
#else
+2 -1
View File
@@ -367,12 +367,13 @@ public:
{
}
static const uint32_t MIN_RATE = 8000;
static const uint32_t MAX_RATE = 640000;
bool IsValid() const override
{
return mChannels > 0 && mChannels <= MAX_AUDIO_CHANNELS
&& mRate > 0 && mRate <= MAX_RATE;
&& mRate >= MIN_RATE && mRate <= MAX_RATE;
}
AudioInfo* GetAsAudioInfo() override
+6
View File
@@ -179,12 +179,18 @@ IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture,
aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aFrame.width * aFrame.height != 0 &&
aPicture.width > 0 &&
aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x >= 0 &&
aPicture.x < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.XMost() <= aFrame.width &&
aPicture.height > 0 &&
aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y >= 0 &&
aPicture.y < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION &&
aPicture.YMost() <= aFrame.height &&
aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT &&
aPicture.width * aPicture.height != 0 &&
aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION &&
+1 -1
View File
@@ -439,7 +439,7 @@ private:
Maybe<size_t> mInitOffset;
Maybe<size_t> mMediaOffset;
bool mValid = true;
char mLastInvalidBox[5];
char mLastInvalidBox[5]{};
};
public:
+14 -5
View File
@@ -20,6 +20,7 @@
#include "WebMBufferedParser.h"
#include "gfx2DGlue.h"
#include "mozilla/Atomics.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/EndianUtils.h"
#include "mozilla/Maybe.h"
#include "mozilla/SharedThreadPool.h"
@@ -352,19 +353,27 @@ WebMDemuxer::ReadMetadata()
mInfo.mVideo.mExtraData = new MediaByteBuffer(length);
mInfo.mVideo.mExtraData->AppendElements(data, length);
break;
}
}
default:
NS_WARNING("Unknown WebM video codec");
return NS_ERROR_FAILURE;
}
// Picture region, taking into account cropping, before scaling
// to the display size.
unsigned int cropH = params.crop_right + params.crop_left;
unsigned int cropV = params.crop_bottom + params.crop_top;
CheckedInt<uint32_t> cropH = CheckedInt<uint32_t>(params.crop_left) + params.crop_right;
CheckedInt<uint32_t> cropV = CheckedInt<uint32_t>(params.crop_top) + params.crop_bottom;
if (!cropH.isValid() || !cropV.isValid() ||
cropH.value() >= params.width || cropV.value() >= params.height) {
WEBM_DEBUG("Invalid crop values left: {} right: {} top: {} bottom: {}",
params.crop_left, params.crop_right, params.crop_top,
params.crop_bottom);
// Ignore invalid crop parameters.
continue;
}
nsIntRect pictureRect(params.crop_left,
params.crop_top,
params.width - cropH,
params.height - cropV);
params.width - cropH.value(),
params.height - cropV.value());
// If the cropping data appears invalid then use the frame data
if (pictureRect.width <= 0 ||
+2
View File
@@ -25,6 +25,8 @@ interface CSSStyleSheet : StyleSheet {
unsigned long insertRule(DOMString rule, optional unsigned long index = 0);
[Throws, NeedsSubjectPrincipal]
void deleteRule(unsigned long index);
[Throws]
void replaceSync(DOMString text);
// Non-standard WebKit things, see https://github.com/w3c/csswg-drafts/pull/3900.
[Throws, NeedsSubjectPrincipal, BinaryName="cssRules"]
+2
View File
@@ -18,6 +18,8 @@ interface mixin DocumentOrShadowRoot {
readonly attribute Element? activeElement;
readonly attribute StyleSheetList styleSheets;
[Throws]
attribute object adoptedStyleSheets;
readonly attribute Element? pointerLockElement;
[LenientSetter, Func="nsDocument::IsUnprefixedFullscreenEnabled"]
File diff suppressed because it is too large. Load diff
+7 -3
View File
@@ -632,9 +632,13 @@ NVImage::GetAsSourceSurface()
// Convert the current NV12 or NV21 data to YUV420P so that we can follow the
// logics in PlanarYCbCrImage::GetAsSourceSurface().
const int bufferLength = mData.mYSize.height * mData.mYStride +
mData.mCbCrSize.height * mData.mCbCrSize.width * 2;
uint8_t* buffer = new uint8_t[bufferLength];
auto bufferLength = CheckedInt<uint32_t>(mData.mYSize.height) * mData.mYStride +
CheckedInt<uint32_t>(mData.mCbCrSize.height) * mData.mCbCrSize.width * 2;
if (!bufferLength.isValid()) {
NS_ERROR("Image buffer length exceeds integer limits.");
return nullptr;
}
uint8_t* buffer = new uint8_t[bufferLength.value()];
Data aData = mData;
aData.mCbCrStride = aData.mCbCrSize.width;
+3 -2
View File
@@ -587,8 +587,9 @@ gfxFontUtils::MapCharToGlyphFormat4(const uint8_t* aBuf, uint32_t aLength,
const AutoSwap_PRUint16* idDelta = &startCodes[segCount];
const AutoSwap_PRUint16* idRangeOffset = &idDelta[segCount];
// Sanity-check that the fixed-size arrays don't exceed the buffer.
const uint8_t* const limit = aBuf + aLength;
// Sanity-check that the fixed-size arrays don't exceed the buffer or the
// current subtable.
const uint8_t* const limit = aBuf + std::min(aLength, uint32_t(cmap4->length));
if ((const uint8_t*)(&idRangeOffset[segCount]) > limit) {
return 0; // broken font, just bail out safely
}
+14 -1
View File
@@ -336,7 +336,20 @@ gfxGraphiteShaper::SetGlyphsFromSegment(DrawTarget *aDrawTarget,
// not a one-to-one mapping with simple metrics: use DetailedGlyph
AutoTArray<gfxShapedText::DetailedGlyph,8> details;
float clusterLoc;
for (uint32_t j = c.baseGlyph; j < c.baseGlyph + c.nGlyphs; ++j) {
uint32_t glyph_start = c.baseGlyph;
uint32_t glyph_end = glyph_start + c.nGlyphs;
if (glyph_end < glyph_start) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (glyph_end - glyph_start > 0xFFFF) {
return NS_ERROR_ILLEGAL_VALUE;
}
if (!details.SetCapacity(glyph_end - glyph_start, fallible)) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t j = glyph_start; j < glyph_end; ++j) {
gfxShapedText::DetailedGlyph* d = details.AppendElement();
d->mGlyphID = gids[j];
d->mYOffset = roundY ? NSToIntRound(-yLocs[j]) * dev2appUnits :
+16 -8
View File
@@ -231,11 +231,13 @@ gfxTextRun::ComputeLigatureData(Range aPartRange,
LigatureData result;
const CompressedGlyph *charGlyphs = mCharacterGlyphs;
uint32_t i;
for (i = aPartRange.start; !charGlyphs[i].IsLigatureGroupStart(); --i) {
NS_ASSERTION(i > 0, "Ligature at the start of the run??");
uint32_t i = aPartRange.start;
while (i && !charGlyphs[i].IsLigatureGroupStart()) {
--i;
}
NS_ASSERTION(charGlyphs[i].IsLigatureGroupStart(), "Ligature at run start?");
result.mRange.start = i;
for (i = aPartRange.start + 1;
i < GetLength() && !charGlyphs[i].IsLigatureGroupStart(); ++i) {
}
@@ -1704,21 +1706,27 @@ gfxFontGroup::GetFontAt(int32_t i, uint32_t aCh)
RefPtr<gfxFont> font = ff.Font();
if (!font) {
gfxFontEntry* fe = mFonts[i].FontEntry();
gfxCharacterMap* unicodeRangeMap = nullptr;
RefPtr<gfxFontEntry> fe = ff.FontEntry();
if (!fe) {
return nullptr;
}
RefPtr<gfxCharacterMap> unicodeRangeMap;
if (fe->mIsUserFontContainer) {
gfxUserFontEntry* ufe = static_cast<gfxUserFontEntry*>(fe);
// This raw pointer is OK because fe holds a strong ref to the object.
gfxUserFontEntry* ufe = static_cast<gfxUserFontEntry*>(fe.get());
if (ufe->LoadState() == gfxUserFontEntry::STATUS_NOT_LOADED &&
ufe->CharacterInUnicodeRange(aCh) &&
!FontLoadingForFamily(ff.Family(), aCh)) {
ufe->Load();
ff.CheckState(mSkipDrawing);
}
unicodeRangeMap = ufe->GetUnicodeRangeMap();
// Update fe to refer to the actual platform font entry, rather than the
// webfont wrapper. After this, we no longer have a strong ref to ufe.
fe = ufe->GetPlatformFontEntry();
if (!fe) {
return nullptr;
}
unicodeRangeMap = ufe->GetUnicodeRangeMap();
}
font = fe->FindOrMakeFont(&mStyle, mFonts[i].NeedsBold(),
unicodeRangeMap);
@@ -2753,7 +2761,7 @@ gfxFontGroup::FindFontForChar(uint32_t aCh, uint32_t aPrevCh, uint32_t aNextCh,
ufe->Load();
ff.CheckState(mSkipDrawing);
}
gfxFontEntry* pfe = ufe->GetPlatformFontEntry();
RefPtr<gfxFontEntry> pfe = ufe->GetPlatformFontEntry();
if (pfe && pfe->HasCharacter(aCh)) {
font = GetFontAt(i, aCh);
if (font) {
+3 -1
View File
@@ -44,7 +44,8 @@ class ExpandingMemoryStream : public ots::OTSStream {
public:
ExpandingMemoryStream(size_t initial, size_t limit)
: mLength(initial), mLimit(limit), mOff(0) {
mPtr = moz_xmalloc(mLength);
mPtr = moz_xmalloc(initial);
std::memset(mPtr, 0, initial);
}
~ExpandingMemoryStream() {
@@ -74,6 +75,7 @@ public:
newLength = mLimit;
}
mPtr = moz_xrealloc(mPtr, newLength);
std::memset(static_cast<char*>(mPtr) + mLength, 0, newLength - mLength);
mLength = newLength;
return WriteRaw(data, length);
}
+7 -4
View File
@@ -1637,10 +1637,13 @@ RasterImage::NotifyDecodeComplete(const DecoderFinalStatus& aStatus,
if (!(aDecoderFlags & DecoderFlags::FIRST_FRAME_ONLY) &&
mHasBeenDecoded && mAnimationState) {
// We've finished a full decode of all animation frames and our AnimationState
// has been notified about them all, so let it know not to expect anymore.
mAnimationState->NotifyDecodeComplete();
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
// If we've successfully finished a full decode of all animation frames
// then let our animation state know it's complete and to not to expect
// any more frames.
if (aStatus.mFinished && !aStatus.mHadError) {
mAnimationState->NotifyDecodeComplete();
mAnimationState->UpdateState(mAnimationFinished, this, mSize);
}
}
// Only act on errors if we have no usable frames from the decoder.
+15 -6
View File
@@ -238,16 +238,21 @@ static inline JS::Value PoisonedObjectValue(JSObject* obj);
namespace detail {
constexpr int CanonicalizedNaNSignBit = 0;
#if defined(__mips__) && !defined(__mips_nan2008)
constexpr uint64_t CanonicalizedNaNSignificand = 0x7FFFFFFFFFFFFULL;
#else
constexpr uint64_t CanonicalizedNaNSignificand = 0x8000000000000ULL;
#endif
// A legacy MIPS ABI can run on hardware whose native NaN encoding does not
// match the encoding selected by the compiler. Determine the canonical NaN
// from an actual floating-point operation during JS initialization.
#if defined(__mips__) && !defined(__mips_nan2008) && \
!defined(__mips_nan_2008)
# define JS_RUNTIME_CANONICAL_NAN
extern JS_PUBLIC_DATA(uint64_t) CanonicalizedNaNBits;
#else
constexpr uint64_t CanonicalizedNaNBits =
mozilla::SpecificNaNBits<double,
detail::CanonicalizedNaNSignBit,
detail::CanonicalizedNaNSignificand>::value;
#endif
} // namespace detail
@@ -260,8 +265,7 @@ constexpr uint64_t CanonicalizedNaNBits =
static MOZ_ALWAYS_INLINE double
GenericNaN()
{
return mozilla::SpecificNaN<double>(detail::CanonicalizedNaNSignBit,
detail::CanonicalizedNaNSignificand);
return mozilla::BitwiseCast<double>(detail::CanonicalizedNaNBits);
}
/* MSVC with PGO miscompiles this function. */
@@ -355,6 +359,11 @@ class MOZ_NON_PARAM alignas(8) Value
}
void setDouble(double d) {
#if defined(JS_RUNTIME_CANONICAL_NAN) && defined(JS_PUNBOX64)
// A non-canonical NaN can overlap the punbox64 tag space. Normalize
// it before storing it so it cannot be mistaken for a GC pointer.
d = CanonicalizeNaN(d);
#endif
// Don't assign to data.asDouble to fix a miscompilation with
// GCC 5.2.1 and 5.3.1. See bug 1312488.
data = layout(d);
+6 -1
View File
@@ -8,8 +8,11 @@
#include "mozilla/CheckedInt.h"
#include "mozilla/TypeTraits.h"
#include <algorithm>
#include "jscntxt.h"
#include "builtin/SelfHostingDefines.h"
#include "irregexp/RegExpParser.h"
#include "jit/InlinableNatives.h"
#include "vm/RegExpStatics.h"
@@ -1754,7 +1757,9 @@ js::RegExpGetSubstitution(JSContext* cx, HandleArrayObject matchResult, HandleLi
// Step 6.
MOZ_ASSERT(position <= string->length());
uint32_t nCaptures = matchResultLength - 1;
// String substitutions can only reference $1 through $99.
uint32_t nCaptures = std::min<uint32_t>(matchResultLength - 1,
REGEXP_MAX_SUBSTITUTION_CAPTURES);
Rooted<CapturesVector> captures(cx, CapturesVector(cx));
if (!captures.reserve(nCaptures))
return false;
+9 -1
View File
@@ -463,6 +463,12 @@ function RegExpGetComplexReplacement(result, matched, S, position,
// Step 14.k.i (reordered).
_DefineDataProperty(captures, capturesLength++, matched);
// String substitutions can only reference $1 through $99. Keep getting and
// stringifying all captures because those operations are observable.
var storedCaptures = functionalReplace ?
nCaptures :
std_Math_min(nCaptures, REGEXP_MAX_SUBSTITUTION_CAPTURES);
// Step 14.g, 14.i, 14.i.iv.
for (var n = 1; n <= nCaptures; n++) {
// Step 14.i.i.
@@ -473,7 +479,9 @@ function RegExpGetComplexReplacement(result, matched, S, position,
capN = ToString(capN);
// Step 14.i.iii.
_DefineDataProperty(captures, capturesLength++, capN);
if (n <= storedCaptures) {
_DefineDataProperty(captures, capturesLength++, capN);
}
}
// Step 14.j.
+2
View File
@@ -79,6 +79,8 @@
#define REGEXP_FLAGS_SLOT 2
#define REGEXP_MAX_SUBSTITUTION_CAPTURES 99
#define REGEXP_IGNORECASE_FLAG 0x01
#define REGEXP_GLOBAL_FLAG 0x02
#define REGEXP_MULTILINE_FLAG 0x04
+3
View File
@@ -494,6 +494,9 @@ OnLeaveBaselineFrame(JSContext* cx, const JitFrameIterator& frame, jsbytecode* p
{
BaselineFrame* baselineFrame = frame.baselineFrame();
if (jit::DebugEpilogue(cx, baselineFrame, pc, frameOk)) {
if (!baselineFrame->hasReturnValue()) {
baselineFrame->setReturnValue(UndefinedValue());
}
rfe->kind = ResumeFromException::RESUME_FORCED_RETURN;
rfe->framePointer = frame.fp() - BaselineFrame::FramePointerOffset;
rfe->stackPointer = reinterpret_cast<uint8_t*>(baselineFrame);
+4 -4
View File
@@ -902,8 +902,8 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void rotateLeft(Imm32 count, Register input, Register dest) PER_SHARED_ARCH;
inline void rotateLeft(Register count, Register input, Register dest) PER_SHARED_ARCH;
inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64);
inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64);
inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp)
DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void rotateLeft64(Register count, Register64 input, Register64 dest, Register temp)
@@ -911,8 +911,8 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void rotateRight(Imm32 count, Register input, Register dest) PER_SHARED_ARCH;
inline void rotateRight(Register count, Register input, Register dest) PER_SHARED_ARCH;
inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64);
inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, loongarch64);
inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp)
DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void rotateRight64(Register count, Register64 input, Register64 dest, Register temp)
@@ -874,6 +874,13 @@ MacroAssembler::branchTestSymbol(Condition cond, Register tag, Label* label)
ma_b(tag, ImmTag(JSVAL_TAG_SYMBOL), label, cond);
}
void
MacroAssembler::branchTestBigInt(Condition cond, Register tag, Label* label)
{
MOZ_ASSERT(cond == Equal || cond == NotEqual);
ma_b(tag, ImmTag(JSVAL_TAG_BIGINT), label, cond);
}
void
MacroAssembler::branchTestSymbol(Condition cond, const BaseIndex& address, Label* label)
{
@@ -614,6 +614,25 @@ CodeGeneratorMIPS64::visitExtendInt32ToInt64(LExtendInt32ToInt64* lir)
masm.ma_sll(output, ToRegister(input), Imm32(0));
}
void
CodeGeneratorMIPS64::visitSignExtendInt64(LSignExtendInt64* lir)
{
Register64 input = ToRegister64(lir->getInt64Operand(0));
Register64 output = ToOutRegister64(lir);
switch (lir->mode()) {
case MSignExtendInt64::Byte:
masm.move8SignExtend(input.reg, output.reg);
break;
case MSignExtendInt64::Half:
masm.move16SignExtend(input.reg, output.reg);
break;
case MSignExtendInt64::Word:
masm.ma_sll(output.reg, input.reg, Imm32(0));
break;
}
}
void
CodeGeneratorMIPS64::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
{
+1
View File
@@ -62,6 +62,7 @@ class CodeGeneratorMIPS64 : public CodeGeneratorMIPSShared
void visitWasmReinterpretFromI64(LWasmReinterpretFromI64* lir);
void visitWasmReinterpretToI64(LWasmReinterpretToI64* lir);
void visitExtendInt32ToInt64(LExtendInt32ToInt64* lir);
void visitSignExtendInt64(LSignExtendInt64* lir);
void visitWrapInt64ToInt32(LWrapInt64ToInt32* lir);
void visitClzI64(LClzI64* lir);
void visitCtzI64(LCtzI64* lir);
+6
View File
@@ -184,3 +184,9 @@ LIRGeneratorMIPS64::visitRandom(MRandom* ins)
temp());
defineFixed(lir, ins, LFloatReg(ReturnDoubleReg));
}
void
LIRGeneratorMIPS64::visitSignExtendInt64(MSignExtendInt64* ins)
{
defineInt64(new(alloc()) LSignExtendInt64(useInt64RegisterAtStart(ins->input())), ins);
}
+1
View File
@@ -46,6 +46,7 @@ class LIRGeneratorMIPS64 : public LIRGeneratorMIPSShared
void visitUnbox(MUnbox* unbox);
void visitReturn(MReturn* ret);
void visitRandom(MRandom* ins);
void visitSignExtendInt64(MSignExtendInt64* ins);
};
typedef LIRGeneratorMIPS64 LIRGeneratorSpecific;
@@ -364,6 +364,18 @@ MacroAssembler::rshift64Arithmetic(Register shift, Register64 dest)
// ===============================================================
// Rotation functions
void
MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest)
{
rotateLeft64(count, src, dest, InvalidReg);
}
void
MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest)
{
rotateLeft64(count, src, dest, InvalidReg);
}
void
MacroAssembler::rotateLeft64(Imm32 count, Register64 src, Register64 dest, Register temp)
{
@@ -382,6 +394,18 @@ MacroAssembler::rotateLeft64(Register count, Register64 src, Register64 dest, Re
ma_drol(dest.reg, src.reg, count);
}
void
MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest)
{
rotateRight64(count, src, dest, InvalidReg);
}
void
MacroAssembler::rotateRight64(Register count, Register64 src, Register64 dest)
{
rotateRight64(count, src, dest, InvalidReg);
}
void
MacroAssembler::rotateRight64(Imm32 count, Register64 src, Register64 dest, Register temp)
{
+8 -3
View File
@@ -1497,17 +1497,17 @@ MacroAssemblerMIPS64Compat::unboxSymbol(Register src, Register dest)
void MacroAssemblerMIPS64Compat::unboxBigInt(const ValueOperand& operand, Register dest)
{
unboxNonDouble(operand, dest, JSVAL_TYPE_BIGINT);
unboxNonDouble(operand, dest);
}
void MacroAssemblerMIPS64Compat::unboxBigInt(Register src, Register dest)
{
unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
ma_dext(dest, src, Imm32(0), Imm32(JSVAL_TAG_SHIFT));
}
void MacroAssemblerMIPS64Compat::unboxBigInt(const Address& src, Register dest)
{
unboxNonDouble(src, dest, JSVAL_TYPE_BIGINT);
unboxNonDouble(src, dest);
}
void
@@ -1559,6 +1559,11 @@ MacroAssemblerMIPS64Compat::unboxPrivate(const ValueOperand& src, Register dest)
void
MacroAssemblerMIPS64Compat::boxDouble(FloatRegister src, const ValueOperand& dest)
{
#if defined(JS_RUNTIME_CANONICAL_NAN)
// Legacy-ABI MIPS hardware can produce NaN payloads that overlap the
// punbox64 tag space. Normalize them before creating a JS::Value.
asMasm().canonicalizeDouble(src);
#endif
as_dmfc1(dest.valueReg(), src);
}
+12
View File
@@ -173,6 +173,18 @@ ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
masm.neg32(ExtractTemp0);
masm.tagValue(JSVAL_TYPE_INT32, ExtractTemp0, R0);
break;
case JSOP_INC: {
masm.unboxInt32(R0, ExtractTemp0);
masm.ma_addTestOverflow(ExtractTemp0, ExtractTemp0, Imm32(1), &failure);
masm.tagValue(JSVAL_TYPE_INT32, ExtractTemp0, R0);
break;
}
case JSOP_DEC: {
masm.unboxInt32(R0, ExtractTemp0);
masm.ma_subTestOverflow(ExtractTemp0, ExtractTemp0, Imm32(1), &failure);
masm.tagValue(JSVAL_TYPE_INT32, ExtractTemp0, R0);
break;
}
default:
MOZ_CRASH("Unexpected op");
return false;
+11 -4
View File
@@ -312,12 +312,19 @@ cvt_s(SprintfState* ss, const char* s, int width, int prec, int flags)
s = generic_null_str(s);
// Limit string length by precision value
int slen = int(generic_strlen(s));
if (0 < prec && prec < slen)
slen = prec;
// We'd want to use strnlen() here, but it is not supported by all targets
// (Most notably old OS X), so use memchr instead.
// Replace with `size_t slen = strnlen(s, size_t(prec));` once we no longer
// need to cater to this.
const char* sptr = (const char*)memchr(s, 0, size_t(prec));
size_t slen = sptr ? sptr - s : size_t(prec);
if (slen > INT_MAX) {
return false;
}
// and away we go
return fill2(ss, s, slen, width, flags);
return fill2(ss, s, int(slen), width, flags);
}
/*
+33
View File
@@ -8,6 +8,8 @@
#include "js/Initialization.h"
#include "mozilla/Assertions.h"
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include <ctype.h>
@@ -19,6 +21,7 @@
#include "jit/ExecutableAllocator.h"
#include "jit/Ion.h"
#include "js/Utility.h"
#include "js/Value.h"
#include "unicode/uclean.h"
#include "unicode/utypes.h"
#include "vm/DateTime.h"
@@ -34,6 +37,31 @@ using js::FutexRuntime;
InitState JS::detail::libraryInitState;
// MIPS-specific
#if defined(JS_RUNTIME_CANONICAL_NAN)
namespace JS {
namespace detail {
JS_PUBLIC_DATA(uint64_t) CanonicalizedNaNBits;
} // namespace detail
} // namespace JS
// MIPS-specific
static void
SetupCanonicalNaN()
{
// Use a real hardware operation. A legacy MIPS ABI can run on hardware
// whose NaN behavior does not match the compiler's predefined NAN value.
volatile double infinity = mozilla::PositiveInfinity<double>();
volatile double hardwareNaN = infinity - infinity;
uint64_t hardwareNaNBits = mozilla::BitwiseCast<uint64_t>(hardwareNaN);
hardwareNaNBits &= ~mozilla::FloatingPoint<double>::kSignBit;
// The selected NaN must remain a double in the JS::Value representation.
MOZ_RELEASE_ASSERT(JS::Value::fromRawBits(hardwareNaNBits).isDouble());
JS::detail::CanonicalizedNaNBits = hardwareNaNBits;
}
#endif
#ifdef DEBUG
static unsigned
MessageParameterCount(const char* format)
@@ -76,6 +104,11 @@ JS::detail::InitWithFailureDiagnostic(bool isDebugBuild)
MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
"how do we have live runtimes before JS_Init?");
// MIPS-specific
#if defined(JS_RUNTIME_CANONICAL_NAN)
SetupCanonicalNaN();
#endif
PRMJ_NowInit();
// The first invocation of `ProcessCreation` creates a temporary thread
+7
View File
@@ -411,6 +411,13 @@ DottedCornerFinder::FindBestOverlap(Float aMinR, Float aMinBorderRadius,
mCount = mMaxCount;
break;
}
// GetCountAndLastOverlap() failed without writing |count| and
// |actualOverlap|: the walk needed more than mMaxCount circles, i.e.
// this overlap produces too many circles. Narrow the search toward
// smaller overlaps.
upper = overlap;
overlap = (upper + lower) / 2.0f;
continue;
}
if (j == 0) {
+38
View File
@@ -13,6 +13,7 @@
#include <algorithm> // For std::max
#include "mozilla/EffectSet.h"
#include "mozilla/EventStates.h"
#include "mozilla/dom/ShadowRoot.h"
#include "nsLayoutUtils.h"
#include "AnimationCommon.h" // For GetLayerAnimationInfo
#include "FrameLayerBuilder.h"
@@ -260,6 +261,7 @@ RestyleManager::ContentStateChanged(nsIContent* aContent,
ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
PostRestyleEvent(aElement, restyleHint, changeHint);
RestyleForHasPseudoClassChange(aElement);
}
// Forwarded nsIMutationObserver method, to handle restyling.
@@ -371,6 +373,30 @@ RestyleManager::AttributeChanged(Element* aElement,
aOldValue,
rsdata);
PostRestyleEvent(aElement, rshint, hint, &rsdata);
RestyleForHasPseudoClassChange(aElement);
}
bool
RestyleManager::RestyleForHasPseudoClassChange(nsINode* aNode)
{
Element* affectedRoot = nullptr;
for (nsINode* node = aNode; node; node = node->GetParentNode()) {
if (!node->GetProperty(nsGkAtoms::hasSelectorDependency)) {
continue;
}
if (node->IsElement()) {
affectedRoot = node->AsElement();
} else if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) {
affectedRoot = shadow->GetHost();
}
}
if (!affectedRoot) {
return false;
}
PostRestyleEvent(affectedRoot, eRestyle_Subtree, nsChangeHint(0));
return true;
}
/* static */ uint64_t
@@ -399,6 +425,10 @@ RestyleManager::RestyleForAppend(nsIContent* aContainer,
nsIContent* aFirstNewContent)
{
// The container cannot be a document, but might be a ShadowRoot.
if (RestyleForHasPseudoClassChange(aContainer)) {
return;
}
if (!aContainer->IsElement()) {
return;
}
@@ -488,6 +518,10 @@ RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
nsIContent* aChild)
{
// The container might be a document or a ShadowRoot.
if (RestyleForHasPseudoClassChange(aContainer)) {
return;
}
if (!aContainer->IsElement()) {
return;
}
@@ -578,6 +612,10 @@ RestyleManager::ContentRemoved(nsINode* aContainer,
nsIContent* aFollowingSibling)
{
// The container might be a document or a ShadowRoot.
if (RestyleForHasPseudoClassChange(aContainer)) {
return;
}
if (!aContainer->IsElement()) {
return;
}
+4
View File
@@ -314,6 +314,10 @@ public:
// the container is null, no work is needed.
void RestyleForAppend(nsIContent* aContainer, nsIContent* aFirstNewContent);
// Restyle a subtree containing any :has() anchor affected by a change at
// or below aNode. Returns true when such a restyle was posted.
bool RestyleForHasPseudoClassChange(nsINode* aNode);
// Process any pending restyles. This should be called after
// CreateNeededFrames.
// Note: It's the caller's responsibility to make sure to wrap a
+17 -8
View File
@@ -5107,19 +5107,28 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
styleMinBSize.GetCoordValue() == 0)) ||
styleMaxBSize.GetUnit() != eStyleUnit_None) {
AspectRatio ratio = aFrame->GetIntrinsicRatio();
AspectRatio ratio = aFrame->GetAspectRatio();
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);
const WritingMode wm = aFrame->GetWritingMode();
LogicalSize boxSizingAdjust(wm);
boxSizingAdjust.ISize(wm) =
GetDefiniteSizeTakenByBoxSizing(boxSizing, aFrame, isInlineAxis,
aFlags & IGNORE_PADDING,
aPercentageBasis);
nscoord bSizeTakenByBoxSizing =
GetDefiniteSizeTakenByBoxSizing(boxSizing, aFrame, !isInlineAxis,
aFlags & IGNORE_PADDING,
aPercentageBasis);
boxSizingAdjust.BSize(wm) = bSizeTakenByBoxSizing;
auto iSizeFromBSize = [&](nscoord aBSize) {
LogicalAxis dependentAxis =
isInlineAxis ? eLogicalAxisInline : eLogicalAxisBlock;
return ratio.ComputeRatioDependentSize(
dependentAxis, wm, aBSize, boxSizingAdjust);
};
// NOTE: This is only the minContentSize if we've been passed MIN_INTRINSIC_ISIZE
// (which is fine, because this should only be used inside a check for that flag).
nscoord minContentSize = result;
@@ -5128,14 +5137,14 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
result = ratio.ApplyTo(h);
result = iSizeFromBSize(h);
}
if (GetDefiniteSize(styleMaxBSize, aFrame, !isInlineAxis, aPercentageBasis, &h) ||
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord maxISize = ratio.ApplyTo(h);
nscoord maxISize = iSizeFromBSize(h);
if (maxISize < result) {
result = maxISize;
}
@@ -5148,7 +5157,7 @@ nsLayoutUtils::IntrinsicForAxis(PhysicalAxis aAxis,
(aPercentageBasis.isNothing() &&
GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord minISize = ratio.ApplyTo(h);
nscoord minISize = iSizeFromBSize(h);
if (minISize > result) {
result = minISize;
}
+5 -1
View File
@@ -8938,7 +8938,11 @@ PresShell::DidDoReflow(bool aInterruptible)
{
mFrameConstructor->EndUpdate();
HandlePostedReflowCallbacks(aInterruptible);
if (!mHandlingCallbacks) {
mHandlingCallbacks = true; // Prevent recursion
HandlePostedReflowCallbacks(aInterruptible);
mHandlingCallbacks = false;
}
nsCOMPtr<nsIDocShell> docShell = mPresContext->GetDocShell();
if (docShell) {
+2
View File
@@ -926,6 +926,8 @@ protected:
bool mAsyncResizeTimerIsActive : 1;
bool mInResize : 1;
bool mHandlingCallbacks : 1;
bool mApproximateFrameVisibilityVisited : 1;
+18 -1
View File
@@ -234,7 +234,18 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
{
WritingMode wm = GetWritingMode();
LogicalSize availSize = aButtonReflowInput.ComputedSize(wm);
availSize.BSize(wm) = NS_INTRINSICSIZE;
// Identify if the inner anonymous block is actually functioning as a flex or grid container.
nsIAtom* kidType = aFirstKid->GetType();
bool isFlexOrGrid = (kidType == nsGkAtoms::flexContainerFrame ||
kidType == nsGkAtoms::gridContainerFrame);
// Preserve the button's definite BSize ONLY for flex/grid children so they
// see a definite containing block main size. For standard buttons, clobber
// to intrinsic so standard vertical centering (extraSpace) calculations work.
if (!isFlexOrGrid || aButtonReflowInput.ComputedBSize() == NS_INTRINSICSIZE) {
availSize.BSize(wm) = NS_INTRINSICSIZE;
}
// shorthand for a value we need to use in a bunch of places
const LogicalMargin& clbp = aButtonReflowInput.ComputedLogicalBorderPadding();
@@ -248,6 +259,12 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
aFirstKid,
availSize);
// Apply the definite BSize directly on the inner reflow input ONLY if it's
// a flex or grid container, allowing it to be used as-is.
if (isFlexOrGrid && aButtonReflowInput.ComputedBSize() != NS_INTRINSICSIZE) {
contentsReflowInput.SetComputedBSize(aButtonReflowInput.ComputedBSize());
}
nsReflowStatus contentsReflowStatus;
ReflowOutput contentsDesiredSize(aButtonReflowInput);
childPos.B(wm) = 0; // This will be set properly later, after reflowing the
+39
View File
@@ -0,0 +1,39 @@
/* 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/. */
#include "mozilla/AspectRatio.h"
#include "mozilla/WritingModes.h"
namespace mozilla {
nscoord
AspectRatio::ComputeRatioDependentSize(
LogicalAxis aRatioDependentAxis,
const WritingMode& aWM,
nscoord aRatioDeterminingSize,
const LogicalSize& aContentBoxToBoxSizingAdjust) const
{
MOZ_DIAGNOSTIC_ASSERT(*this);
LogicalSize adjust(aWM);
if (mUseBoxSizing == UseBoxSizing::Yes) {
adjust = aContentBoxToBoxSizingAdjust;
}
AspectRatio logicalRatio = aWM.IsVertical() ? Inverted() : *this;
nscoord result;
if (aRatioDependentAxis == eLogicalAxisInline) {
result = logicalRatio.ApplyTo(aRatioDeterminingSize +
adjust.BSize(aWM)) -
adjust.ISize(aWM);
} else {
result = logicalRatio.Inverted().ApplyTo(aRatioDeterminingSize +
adjust.ISize(aWM)) -
adjust.BSize(aWM);
}
return std::max(nscoord(0), result);
}
} // namespace mozilla
+45 -7
View File
@@ -9,21 +9,46 @@
/* The aspect ratio of a box, in a "width / height" format. */
#include "mozilla/Attributes.h"
#include "mozilla/LogicalTypes.h"
#include "nsCoord.h"
#include "nsSize.h"
#include <algorithm>
#include <limits>
namespace mozilla {
struct AspectRatio {
AspectRatio() : mRatio(0.0f) {}
explicit AspectRatio(float aRatio) : mRatio(std::max(aRatio, 0.0f)) {}
class LogicalSize;
class WritingMode;
static AspectRatio FromSize(float aWidth, float aHeight) {
enum class UseBoxSizing : uint8_t {
// Natural ratios and "auto <ratio>" always use content-box dimensions.
No,
// A specified <ratio> uses the dimensions selected by box-sizing.
Yes,
};
struct AspectRatio {
AspectRatio()
: mRatio(0.0f)
, mUseBoxSizing(UseBoxSizing::No)
{}
explicit AspectRatio(float aRatio,
UseBoxSizing aUseBoxSizing = UseBoxSizing::No)
: mRatio(std::max(aRatio, 0.0f))
, mUseBoxSizing(aUseBoxSizing)
{}
static AspectRatio FromSize(float aWidth, float aHeight,
UseBoxSizing aUseBoxSizing = UseBoxSizing::No) {
if (aWidth == 0.0f || aHeight == 0.0f) {
return AspectRatio();
}
return AspectRatio(aWidth / aHeight);
float ratio = aWidth / aHeight;
if (!std::isfinite(ratio)) {
return AspectRatio();
}
return AspectRatio(ratio, aUseBoxSizing);
}
static AspectRatio FromSize(nsSize aSize) {
@@ -55,11 +80,23 @@ struct AspectRatio {
// 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));
std::max(std::numeric_limits<float>::epsilon(), 1.0f / mRatio),
mUseBoxSizing);
}
/**
* Computes a content-box size in the ratio-dependent axis from a
* content-box size in the ratio-determining axis.
*/
nscoord ComputeRatioDependentSize(
LogicalAxis aRatioDependentAxis,
const WritingMode& aWM,
nscoord aRatioDeterminingSize,
const LogicalSize& aContentBoxToBoxSizingAdjust) const;
bool operator==(const AspectRatio& aOther) const {
return mRatio == aOther.mRatio;
return mRatio == aOther.mRatio &&
mUseBoxSizing == aOther.mUseBoxSizing;
}
bool operator!=(const AspectRatio& aOther) const {
@@ -73,6 +110,7 @@ struct AspectRatio {
private:
// 0.0f represents no aspect ratio.
float mRatio;
UseBoxSizing mUseBoxSizing;
};
} // namespace mozilla
+37
View File
@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_LogicalTypes_h
#define mozilla_LogicalTypes_h
namespace mozilla {
// Logical axis, edge, side and corner constants for use in various places.
enum LogicalAxis {
eLogicalAxisBlock = 0x0,
eLogicalAxisInline = 0x1
};
enum LogicalEdge {
eLogicalEdgeStart = 0x0,
eLogicalEdgeEnd = 0x1
};
enum LogicalSide {
eLogicalSideBStart = (eLogicalAxisBlock << 1) | eLogicalEdgeStart, // 0x0
eLogicalSideBEnd = (eLogicalAxisBlock << 1) | eLogicalEdgeEnd, // 0x1
eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart, // 0x2
eLogicalSideIEnd = (eLogicalAxisInline << 1) | eLogicalEdgeEnd // 0x3
};
enum LogicalCorner
{
eLogicalCornerBStartIStart = 0,
eLogicalCornerBStartIEnd = 1,
eLogicalCornerBEndIEnd = 2,
eLogicalCornerBEndIStart = 3
};
} // namespace mozilla
#endif // mozilla_LogicalTypes_h
+1
View File
@@ -6,6 +6,7 @@
#ifndef WritingModes_h_
#define WritingModes_h_
#include "mozilla/LogicalTypes.h"
#include "nsRect.h"
#include "nsStyleContext.h"
#include "nsBidiUtils.h"
+2
View File
@@ -110,6 +110,7 @@ EXPORTS += [
EXPORTS.mozilla += [
'AspectRatio.h',
'CSSAlignUtils.h',
'LogicalTypes.h',
'ReflowInput.h',
'ReflowOutput.h',
'WritingModes.h',
@@ -124,6 +125,7 @@ EXPORTS.mozilla.layout += [
]
UNIFIED_SOURCES += [
'AspectRatio.cpp',
'AsyncScrollBase.cpp',
'BlockReflowInput.cpp',
'CSSAlignUtils.cpp',
+1 -1
View File
@@ -1945,7 +1945,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput,
: mFrame(aFlexItemReflowInput.mFrame),
mFlexGrow(aFlexGrow),
mFlexShrink(aFlexShrink),
mIntrinsicRatio(mFrame->GetIntrinsicRatio()),
mIntrinsicRatio(mFrame->GetAspectRatio()),
mBorderPadding(aFlexItemReflowInput.ComputedPhysicalBorderPadding()),
mMargin(aFlexItemReflowInput.ComputedPhysicalMargin()),
mMainMinSize(aMainMinSize),
+67 -26
View File
@@ -4655,10 +4655,44 @@ nsFrame::GetIntrinsicSize()
/* virtual */ AspectRatio
nsFrame::GetIntrinsicRatio()
{
const nsStylePosition* stylePos = StylePosition();
return stylePos->mAspectRatio == 0.0f
? AspectRatio()
: AspectRatio(stylePos->mAspectRatio);
return AspectRatio();
}
AspectRatio
nsIFrame::GetAspectRatio()
{
// The property does not apply to inline boxes or internal ruby/table boxes.
nsIAtom* type = GetType();
if (type == nsGkAtoms::inlineFrame ||
RubyUtils::IsRubyBox(type) ||
type == nsGkAtoms::tableCellFrame ||
type == nsGkAtoms::tableColFrame ||
type == nsGkAtoms::tableColGroupFrame ||
type == nsGkAtoms::tableRowFrame ||
type == nsGkAtoms::tableRowGroupFrame) {
return AspectRatio();
}
const StyleAspectRatio& styleRatio = StylePosition()->mAspectRatio;
// A non-auto, non-degenerate ratio overrides the natural ratio and uses the
// box selected by box-sizing.
if (!styleRatio.mAuto && styleRatio.HasUsableRatio()) {
return AspectRatio::FromSize(styleRatio.mWidth, styleRatio.mHeight,
UseBoxSizing::Yes);
}
if (AspectRatio intrinsicRatio = GetIntrinsicRatio()) {
return intrinsicRatio;
}
// The fallback in "auto <ratio>" always operates on the content box.
if (styleRatio.HasUsableRatio()) {
return AspectRatio::FromSize(styleRatio.mWidth, styleRatio.mHeight,
UseBoxSizing::No);
}
return AspectRatio();
}
void
@@ -4727,11 +4761,11 @@ nsFrame::ComputeSize(nsRenderingContext* aRenderingContext,
const LogicalSize& aPadding,
ComputeSizeFlags aFlags)
{
AspectRatio intrinsicRatio = GetIntrinsicRatio();
if (intrinsicRatio) {
AspectRatio aspectRatio = GetAspectRatio();
if (aspectRatio) {
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
GetIntrinsicSize(),
intrinsicRatio,
aspectRatio,
aCBSize, aMargin,
aBorder, aPadding,
aFlags);
@@ -4976,8 +5010,6 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
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);
@@ -5039,6 +5071,14 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
if (stylePos->mBoxSizing == StyleBoxSizing::Border) {
boxSizingAdjust = aBorder + aPadding;
}
auto iSizeFromBSize = [&](nscoord aBSize) {
return aIntrinsicRatio.ComputeRatioDependentSize(
eLogicalAxisInline, aWM, aBSize, boxSizingAdjust);
};
auto bSizeFromISize = [&](nscoord aISize) {
return aIntrinsicRatio.ComputeRatioDependentSize(
eLogicalAxisBlock, aWM, aISize, boxSizingAdjust);
};
nscoord boxSizingToMarginEdgeISize =
aMargin.ISize(aWM) + aBorder.ISize(aWM) + aPadding.ISize(aWM) -
boxSizingAdjust.ISize(aWM);
@@ -5129,7 +5169,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
bSize = nsLayoutUtils::ComputeBSizeValue(aCBSize.BSize(aWM),
boxSizingAdjust.BSize(aWM),
*blockStyleCoord);
} else if (MOZ_UNLIKELY(isGridItem)) {
} else if (MOZ_UNLIKELY(isGridItem) &&
!(aFlags & nsIFrame::eUseAutoBSize)) {
MOZ_ASSERT(!IS_TRUE_OVERFLOW_CONTAINER(this));
// 'auto' block-size for grid-level box - apply 'stretch' as needed:
auto cbSize = aCBSize.BSize(aWM);
@@ -5230,9 +5271,9 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
if (hasIntrinsicISize) {
tentISize = intrinsicISize;
} else if (hasIntrinsicBSize && logicalRatio) {
tentISize = logicalRatio.ApplyTo(intrinsicBSize);
} else if (logicalRatio) {
} else if (hasIntrinsicBSize && aIntrinsicRatio) {
tentISize = iSizeFromBSize(intrinsicBSize);
} else if (aIntrinsicRatio) {
tentISize = aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
if (tentISize < 0) tentISize = 0;
} else {
@@ -5249,8 +5290,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
if (hasIntrinsicBSize) {
tentBSize = intrinsicBSize;
} else if (logicalRatio) {
tentBSize = logicalRatio.Inverted().ApplyTo(tentISize);
} else if (aIntrinsicRatio) {
tentBSize = bSizeFromISize(tentISize);
} else {
tentBSize = nsPresContext::CSSPixelsToAppUnits(150);
}
@@ -5261,39 +5302,39 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
}
if (logicalRatio) {
if (aIntrinsicRatio) {
if (stretchI == eStretch) {
tentISize = iSize; // * / 'stretch'
if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / 'stretch'
} else if (stretchB == eStretchPreservingRatio) {
// 'normal' / 'stretch'
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
tentBSize = bSizeFromISize(iSize);
}
} else if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / * (except 'stretch')
if (stretchI == eStretchPreservingRatio) {
// 'stretch' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
tentISize = iSizeFromBSize(bSize);
}
} else if (stretchI == eStretchPreservingRatio) {
tentISize = iSize; // * (except 'stretch') / 'normal'
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
tentBSize = bSizeFromISize(iSize);
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
// Stretch within the CB size with preserved intrinsic ratio.
tentBSize = bSize; // 'normal' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
tentISize = iSizeFromBSize(bSize);
}
} else if (stretchB == eStretchPreservingRatio) {
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
tentISize = logicalRatio.ApplyTo(bSize);
tentISize = iSizeFromBSize(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 (logicalRatio && stretchI != eStretch && stretchB != eStretch) {
if (aIntrinsicRatio && stretchI != eStretch && stretchB != eStretch) {
nsSize autoSize = nsLayoutUtils::
ComputeAutoSizeWithIntrinsicDimensions(minISize, minBSize,
maxISize, maxBSize,
@@ -5314,8 +5355,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
// 'auto' iSize, non-'auto' bSize
bSize = NS_CSS_MINMAX(bSize, minBSize, maxBSize);
if (stretchI != eStretch) {
if (logicalRatio) {
iSize = logicalRatio.ApplyTo(bSize);
if (aIntrinsicRatio) {
iSize = iSizeFromBSize(bSize);
} else if (hasIntrinsicISize) {
if (!((aFlags & ComputeSizeFlags::eIClampMarginBoxMinSize) &&
intrinsicISize > iSize)) {
@@ -5334,8 +5375,8 @@ nsFrame::ComputeSizeWithIntrinsicDimensions(nsRenderingContext* aRenderingConte
// non-'auto' iSize, 'auto' bSize
iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
if (stretchB != eStretch) {
if (logicalRatio) {
bSize = logicalRatio.Inverted().ApplyTo(iSize);
if (aIntrinsicRatio) {
bSize = bSizeFromISize(iSize);
} else if (hasIntrinsicBSize) {
if (!((aFlags & ComputeSizeFlags::eBClampMarginBoxMinSize) &&
intrinsicBSize > bSize)) {
+5 -1
View File
@@ -318,7 +318,11 @@ nsHTMLFramesetFrame::Init(nsIContent* aContent,
mChildFrameborder[mChildCount] = GetFrameBorder(child);
mChildBorderColors[mChildCount].Set(GetBorderColor(child));
}
child->SetPrimaryFrame(frame);
if (MOZ_LIKELY(!child->GetPrimaryFrame())) {
// Child might have a pre-existing primary frame if we're doing fixed-pos
// replication... So, only set it if there is no primary frame yet.
child->SetPrimaryFrame(frame);
}
mFrames.AppendFrame(nullptr, frame);
+1 -2
View File
@@ -225,7 +225,7 @@ nsHTMLCanvasFrame::ComputeSize(nsRenderingContext *aRenderingContext,
intrinsicSize.width.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.width));
intrinsicSize.height.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(size.height));
AspectRatio intrinsicRatio = GetIntrinsicRatio();
AspectRatio intrinsicRatio = GetAspectRatio();
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, intrinsicRatio,
@@ -424,4 +424,3 @@ nsHTMLCanvasFrame::GetFrameName(nsAString& aResult) const
return MakeFrameName(NS_LITERAL_STRING("HTMLCanvas"), aResult);
}
#endif
+6
View File
@@ -2078,6 +2078,12 @@ public:
virtual mozilla::IntrinsicSize GetIntrinsicSize() = 0;
/**
* Get the preferred aspect ratio after applying the aspect-ratio property
* to this frame's natural ratio.
*/
mozilla::AspectRatio GetAspectRatio();
/**
* Get the intrinsic ratio of this element, or a default-constructed
* AspectRatio if it has no intrinsic ratio.
+6 -4
View File
@@ -320,7 +320,7 @@ ComputeIntrinsicSize(imgIContainer* aImage,
}
*/
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) {
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio.HasRatio()) {
return IntrinsicSize();
}
@@ -375,8 +375,10 @@ ComputeAspectRatio(imgIContainer* aImage,
return fromImage;
}
}
if (aUseMappedRatio && aFrame.StylePosition()->mAspectRatio != 0.0f) {
return AspectRatio(aFrame.StylePosition()->mAspectRatio);
if (aUseMappedRatio &&
aFrame.StylePosition()->mAspectRatio.HasUsableRatio()) {
const StyleAspectRatio& ratio = aFrame.StylePosition()->mAspectRatio;
return AspectRatio::FromSize(ratio.mWidth, ratio.mHeight);
}
if (aFrame.ShouldShowBrokenImageIcon()) {
return AspectRatio(1.0f);
@@ -891,7 +893,7 @@ nsImageFrame::ComputeSize(nsRenderingContext *aRenderingContext,
}
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, mIntrinsicRatio,
intrinsicSize, GetAspectRatio(),
aCBSize, aMargin, aBorder, aPadding,
aFlags);
}
+1 -1
View File
@@ -786,7 +786,7 @@ IsPercentageAware(const nsIFrame* aFrame)
// is calculated from the constraint equation used for
// block-level, non-replaced elements in normal flow.
nsIFrame *f = const_cast<nsIFrame*>(aFrame);
if (f->GetIntrinsicRatio() &&
if (f->GetAspectRatio() &&
// Some percents are treated like 'auto', so check != coord
pos->mHeight.GetUnit() != eStyleUnit_Coord) {
const IntrinsicSize &intrinsicSize = f->GetIntrinsicSize();
+1 -1
View File
@@ -721,7 +721,7 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext* aRenderingContext,
if (subDocRoot) {
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
subDocRoot->GetIntrinsicSize(),
subDocRoot->GetIntrinsicRatio(),
GetAspectRatio(),
aCBSize, aMargin, aBorder,
aPadding, aFlags);
}
+1 -6
View File
@@ -543,13 +543,8 @@ nsVideoFrame::ComputeSize(nsRenderingContext *aRenderingContext,
intrinsicSize.width.SetCoordValue(size.width);
intrinsicSize.height.SetCoordValue(size.height);
// Only video elements have an intrinsic ratio.
auto intrinsicRatio = HasVideoElement() ?
AspectRatio::FromSize(size) :
AspectRatio();
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, intrinsicRatio,
intrinsicSize, GetAspectRatio(),
aCBSize, aMargin, aBorder, aPadding,
aFlags);
}
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Grid: aspect-ratio contributes to an auto row reference</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.gallery {
display: grid;
width: 640px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
padding: 30px;
}
.item {
position: relative;
height: 280px;
overflow: hidden;
}
.item > div {
width: 100%;
height: 100%;
background: green;
}
</style>
</head>
<body>
<div class="gallery">
<div class="item"><div></div></div>
<div class="item"><div></div></div>
</div>
</body>
</html>
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Grid: aspect-ratio contributes to an auto row</title>
<link rel="match" href="grid-item-aspect-ratio-001-ref.html">
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.gallery {
display: grid;
width: 640px;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 20px;
padding: 30px;
}
.item {
position: relative;
aspect-ratio: 1;
overflow: hidden;
background: red;
}
.item > div {
width: 100%;
height: 100%;
background: green;
}
</style>
</head>
<body>
<div class="gallery">
<div class="item"><div></div></div>
<div class="item"><div></div></div>
</div>
</body>
</html>
+1
View File
@@ -280,5 +280,6 @@ asserts(0-10) == grid-fragmentation-015.html grid-fragmentation-015-ref.html # b
== grid-fragmentation-dyn2-031.html grid-fragmentation-031-ref.html
== bug1306106.html bug1306106-ref.html
== grid-percent-intrinsic-sizing-001.html grid-percent-intrinsic-sizing-001-ref.html
== grid-item-aspect-ratio-001.html grid-item-aspect-ratio-001-ref.html
== bug1349571.html bug1349571-ref.html
== bug1356820.html bug1356820-ref.html
+86
View File
@@ -1781,6 +1781,7 @@ CSSStyleSheet::DidDirty()
MOZ_ASSERT(!mInner->mComplete || mDirty,
"caller must have called WillDirty()");
ClearRuleCascades();
NotifyAdopterRuleChanged();
}
void
@@ -1877,6 +1878,11 @@ CSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
// Hierarchy checking.
int32_t newType = rule->GetType();
if (IsConstructed() && newType == css::Rule::IMPORT_RULE) {
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
return 0;
}
// check that we're not inserting before a charset rule
css::Rule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex);
if (nextRule) {
@@ -1987,6 +1993,86 @@ CSSStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
}
}
void
CSSStyleSheet::ReplaceSyncInternal(const nsAString& aText, ErrorResult& aRv)
{
MOZ_ASSERT(mInner->mComplete);
RefPtr<CSSStyleSheet> parsedSheet =
new CSSStyleSheet(mParsingMode, GetCORSMode(), GetReferrerPolicy());
parsedSheet->SetURIs(mInner->mSheetURI, mInner->mOriginalSheetURI,
mInner->mBaseURI);
parsedSheet->SetPrincipal(mInner->mPrincipal);
parsedSheet->SetComplete();
nsCSSParser parser(nullptr, parsedSheet);
nsresult rv = parser.ParseSheet(aText, parsedSheet->GetSheetURI(),
parsedSheet->GetBaseURI(),
parsedSheet->Principal(), 1);
if (NS_FAILED(rv)) {
parsedSheet->mInner->mOrderedRules.EnumerateForwards(SetStyleSheetReference,
nullptr);
parsedSheet->mInner->mOrderedRules.Clear();
}
for (int32_t index = parsedSheet->mInner->mOrderedRules.Count() - 1;
index >= 0; --index) {
RefPtr<css::Rule> rule = parsedSheet->mInner->mOrderedRules.ObjectAt(index);
if (rule->GetType() == css::Rule::IMPORT_RULE) {
parsedSheet->mInner->mOrderedRules.RemoveObjectAt(index);
rule->SetStyleSheet(nullptr);
}
}
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
WillDirty();
while (mInner->mOrderedRules.Count() != 0) {
RefPtr<css::Rule> rule =
mInner->mOrderedRules.ObjectAt(mInner->mOrderedRules.Count() - 1);
mInner->mOrderedRules.RemoveObjectAt(mInner->mOrderedRules.Count() - 1);
rule->SetStyleSheet(nullptr);
if (mDocument) {
mDocument->StyleRuleRemoved(this, rule);
}
}
for (CSSStyleSheet* child = mInner->mFirstChild; child; ) {
NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!");
CSSStyleSheet* next = child->mNext;
child->mParent = nullptr;
child->mDocument = nullptr;
child->mNext = nullptr;
child = next;
}
mInner->mFirstChild = nullptr;
mInner->mNameSpaceMap = nullptr;
for (int32_t index = 0; index < parsedSheet->mInner->mOrderedRules.Count();
++index) {
RefPtr<css::Rule> rule = parsedSheet->mInner->mOrderedRules.ObjectAt(index);
if (!mInner->mOrderedRules.AppendObject(rule)) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return;
}
rule->SetStyleSheet(this);
}
parsedSheet->mInner->mOrderedRules.Clear();
parsedSheet->mInner->mNameSpaceMap = nullptr;
mInner->RebuildNameSpaces();
DidDirty();
if (mDocument) {
for (int32_t index = 0; index < mInner->mOrderedRules.Count(); ++index) {
RefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(index);
mDocument->StyleRuleAdded(this, rule);
}
}
}
nsresult
CSSStyleSheet::DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex)
{
+1
View File
@@ -253,6 +253,7 @@ protected:
uint32_t InsertRuleInternal(const nsAString& aRule,
uint32_t aIndex, ErrorResult& aRv);
void DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv);
void ReplaceSyncInternal(const nsAString& aText, ErrorResult& aRv);
RefPtr<nsMediaList> mMedia;
RefPtr<CSSStyleSheet> mNext;
+109
View File
@@ -32,6 +32,8 @@
#include "nsIFrame.h"
#include "gfx2DGlue.h"
#include <cmath>
using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::gfx;
@@ -39,6 +41,35 @@ using nsStyleTransformMatrix::Decompose2DMatrix;
using nsStyleTransformMatrix::Decompose3DMatrix;
using nsStyleTransformMatrix::ShearType;
static bool
GetAspectRatioAnimationValue(const nsCSSValuePair* aPair,
bool& aAuto,
float& aRatio)
{
aAuto = aPair->mXValue.GetUnit() == eCSSUnit_Auto;
if (aAuto) {
if (aPair->mYValue.GetUnit() != eCSSUnit_Pair) {
return false;
}
aPair = &aPair->mYValue.GetPairValue();
}
if (aPair->mXValue.GetUnit() != eCSSUnit_Number ||
aPair->mYValue.GetUnit() != eCSSUnit_Number) {
return false;
}
float width = aPair->mXValue.GetFloatValue();
float height = aPair->mYValue.GetFloatValue();
if (width <= 0.0f || height <= 0.0f ||
!std::isfinite(width) || !std::isfinite(height)) {
return false;
}
aRatio = width / height;
return std::isfinite(aRatio) && aRatio > 0.0f;
}
// HELPER METHODS
// --------------
/*
@@ -1243,6 +1274,21 @@ StyleAnimationValue::ComputeDistance(nsCSSPropertyID aProperty,
case eUnit_CSSValuePair: {
const nsCSSValuePair *pair1 = aStartValue.GetCSSValuePairValue();
const nsCSSValuePair *pair2 = aEndValue.GetCSSValuePairValue();
if (aProperty == eCSSProperty_aspect_ratio) {
bool auto1;
bool auto2;
float ratio1;
float ratio2;
if (!GetAspectRatioAnimationValue(pair1, auto1, ratio1) ||
!GetAspectRatioAnimationValue(pair2, auto2, ratio2) ||
auto1 != auto2) {
return false;
}
aDistance = Abs(std::log(double(ratio2)) -
std::log(double(ratio1)));
return true;
}
nsCSSUnit unit[2];
unit[0] = GetCommonUnit(aProperty, pair1->mXValue.GetUnit(),
pair2->mXValue.GetUnit());
@@ -2821,6 +2867,42 @@ StyleAnimationValue::AddWeighted(nsCSSPropertyID aProperty,
return true;
}
case eUnit_CSSValuePair: {
if (aProperty == eCSSProperty_aspect_ratio) {
bool auto1;
bool auto2;
float ratio1;
float ratio2;
if (!GetAspectRatioAnimationValue(aValue1.GetCSSValuePairValue(),
auto1, ratio1) ||
!GetAspectRatioAnimationValue(aValue2.GetCSSValuePairValue(),
auto2, ratio2) ||
auto1 != auto2 ||
std::abs((aCoeff1 + aCoeff2) - 1.0) > 0.000001) {
return false;
}
float resultRatio =
std::exp(aCoeff1 * std::log(double(ratio1)) +
aCoeff2 * std::log(double(ratio2)));
nsCSSValue width;
width.SetFloatValue(resultRatio, eCSSUnit_Number);
nsCSSValue height;
height.SetFloatValue(1.0f, eCSSUnit_Number);
nsCSSValue ratio;
ratio.SetPairValue(width, height);
auto result = MakeUnique<nsCSSValuePair>();
if (auto1) {
result->mXValue.SetAutoValue();
result->mYValue = ratio;
} else {
*result = ratio.GetPairValue();
}
aResultValue.SetAndAdoptCSSValuePairValue(result.release(),
eUnit_CSSValuePair);
return true;
}
uint32_t restrictions = nsCSSProps::ValueRestrictions(aProperty);
Maybe<nsCSSValuePair> result =
AddCSSValuePair(aProperty, restrictions,
@@ -4031,6 +4113,33 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
break;
}
case eCSSProperty_aspect_ratio: {
const StyleAspectRatio& ratio =
static_cast<const nsStylePosition*>(styleStruct)->mAspectRatio;
if (!ratio.HasRatio()) {
aComputedValue.SetAutoValue();
break;
}
nsCSSValue width;
width.SetFloatValue(ratio.mWidth, eCSSUnit_Number);
nsCSSValue height;
height.SetFloatValue(ratio.mHeight, eCSSUnit_Number);
nsCSSValue ratioValue;
ratioValue.SetPairValue(width, height);
auto pair = MakeUnique<nsCSSValuePair>();
if (ratio.mAuto) {
pair->mXValue.SetAutoValue();
pair->mYValue = ratioValue;
} else {
*pair = ratioValue.GetPairValue();
}
aComputedValue.SetAndAdoptCSSValuePairValue(pair.release(),
eUnit_CSSValuePair);
break;
}
case eCSSProperty_border_spacing: {
const nsStyleTableBorder *styleTableBorder =
static_cast<const nsStyleTableBorder*>(styleStruct);
+30 -2
View File
@@ -993,7 +993,8 @@ nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
nsCSSSelectorList::nsCSSSelectorList(void)
: mSelectors(nullptr),
mWeight(0),
mNext(nullptr)
mNext(nullptr),
mIsRelativeSelector(false)
{
MOZ_COUNT_CTOR(nsCSSSelectorList);
}
@@ -1047,7 +1048,33 @@ nsCSSSelectorList::ToString(nsAString& aResult, CSSStyleSheet* aSheet)
return;
}
for (;;) {
p->mSelectors->ToString(aResult, aSheet, true);
if (p->mIsRelativeSelector) {
// :has() arguments are represented internally as selectors with an
// implicit leftmost anchor. Serialize the authored relative selector,
// including an explicit leading combinator when there is one.
const nsCSSSelector* leftmost = p->mSelectors;
while (leftmost->mNext && leftmost->mNext->mNext) {
leftmost = leftmost->mNext;
}
MOZ_ASSERT(leftmost->mNext,
"relative selector should have an implicit anchor");
if (leftmost->mNext->mOperator != char16_t(' ')) {
aResult.Append(leftmost->mNext->mOperator);
aResult.Append(char16_t(' '));
}
nsAutoPtr<nsCSSSelector> selectors(p->mSelectors->Clone());
nsCSSSelector* beforeAnchor = selectors;
while (beforeAnchor->mNext && beforeAnchor->mNext->mNext) {
beforeAnchor = beforeAnchor->mNext;
}
MOZ_ASSERT(beforeAnchor->mNext);
delete beforeAnchor->mNext;
beforeAnchor->mNext = nullptr;
selectors->ToString(aResult, aSheet, true);
} else {
p->mSelectors->ToString(aResult, aSheet, true);
}
p = p->mNext;
if (!p)
break;
@@ -1060,6 +1087,7 @@ nsCSSSelectorList::Clone(bool aDeep) const
{
nsCSSSelectorList *result = new nsCSSSelectorList();
result->mWeight = mWeight;
result->mIsRelativeSelector = mIsRelativeSelector;
NS_IF_CLONE(mSelectors);
if (aDeep) {
+4
View File
@@ -314,6 +314,10 @@ struct nsCSSSelectorList {
nsCSSSelector* mSelectors;
int32_t mWeight;
nsCSSSelectorList* mNext;
// Relative selector lists used by :has() have an implicit internal anchor
// stored as their leftmost selector. This flag keeps that implementation
// detail out of serialization and is preserved by cloning.
bool mIsRelativeSelector;
protected:
friend class inDOMUtils;
nsCSSSelectorList* Clone(bool aDeep) const;
+78 -1
View File
@@ -26,6 +26,9 @@ StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode)
, mOwningNode(nullptr)
, mParsingMode(aParsingMode)
, mDisabled(false)
, mConstructed(false)
, mDisallowModification(false)
, mAdoptionCount(0)
, mDocumentAssociationMode(NotOwnedByDocument)
{
}
@@ -38,6 +41,9 @@ StyleSheet::StyleSheet(const StyleSheet& aCopy,
, mOwningNode(aOwningNodeToUse)
, mParsingMode(aCopy.mParsingMode)
, mDisabled(aCopy.mDisabled)
, mConstructed(aCopy.mConstructed)
, mDisallowModification(false)
, mAdoptionCount(0)
// We only use this constructor during cloning. It's the cloner's
// responsibility to notify us if we end up being owned by a document.
, mDocumentAssociationMode(NotOwnedByDocument)
@@ -54,7 +60,7 @@ NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet)
NS_IMPL_CYCLE_COLLECTING_RELEASE(StyleSheet)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheet)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(StyleSheet, mConstructorDocument)
mozilla::dom::CSSStyleSheetParsingMode
StyleSheet::ParsingModeDOM()
@@ -254,10 +260,70 @@ StyleSheet::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
sheet->SetURIs(documentURI, nullptr, baseURI);
sheet->SetPrincipal(principal);
sheet->SetComplete();
sheet->SetConstructed();
sheet->SetConstructorDocument(document);
return sheet.forget();
}
void
StyleSheet::AddAdopter(nsIDocument* aDocument)
{
MOZ_ASSERT(IsConstructed());
MOZ_ASSERT(aDocument);
MOZ_ASSERT(ConstructorDocument() == aDocument);
if (mAdoptionCount++ == 0) {
SetAssociatedDocument(aDocument, NotOwnedByDocument);
}
}
void
StyleSheet::AddAdopter(dom::ShadowRoot* aShadowRoot)
{
MOZ_ASSERT(aShadowRoot);
mAdopterShadowRoots.AppendElement(aShadowRoot);
AddAdopter(aShadowRoot->OwnerDoc());
}
void
StyleSheet::RemoveAdopter(nsIDocument* aDocument)
{
MOZ_ASSERT(IsConstructed());
MOZ_ASSERT(aDocument);
MOZ_ASSERT(ConstructorDocument() == aDocument);
MOZ_ASSERT(mAdoptionCount > 0);
if (mAdoptionCount == 0) {
return;
}
if (--mAdoptionCount == 0 && !IsOwnedByDocument()) {
ClearAssociatedDocument();
}
}
void
StyleSheet::RemoveAdopter(dom::ShadowRoot* aShadowRoot)
{
MOZ_ASSERT(aShadowRoot);
mAdopterShadowRoots.RemoveElement(aShadowRoot);
RemoveAdopter(aShadowRoot->OwnerDoc());
}
void
StyleSheet::NotifyAdopterRuleChanged()
{
for (size_t i = 0; i < mAdopterShadowRoots.Length(); ++i) {
dom::ShadowRoot* shadowRoot = mAdopterShadowRoots[i];
if (mAdopterShadowRoots.IndexOf(shadowRoot) == i) {
shadowRoot->StyleSheetChanged();
}
}
}
dom::CSSRuleList*
StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv)
@@ -290,6 +356,17 @@ StyleSheet::DeleteRule(uint32_t aIndex,
AsConcrete()->DeleteRuleInternal(aIndex, aRv);
}
void
StyleSheet::ReplaceSync(const nsAString& aText, ErrorResult& aRv)
{
if (!IsConstructed() || IsModificationDisallowed()) {
aRv.Throw(NS_ERROR_DOM_NOT_ALLOWED_ERR);
return;
}
AsConcrete()->ReplaceSyncInternal(aText, aRv);
}
int32_t
StyleSheet::AddRule(const nsAString& aSelector, const nsAString& aBlock,
const Optional<uint32_t>& aIndex,
+24
View File
@@ -12,6 +12,7 @@
#include "mozilla/CORSMode.h"
#include "nsIDOMCSSStyleSheet.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
class nsIDocument;
@@ -26,6 +27,7 @@ struct StyleSheetInfo;
namespace dom {
class CSSRuleList;
class ShadowRoot;
class SRIMetadata;
} // namespace dom
@@ -160,6 +162,7 @@ public:
void DeleteRule(uint32_t aIndex,
nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv);
void ReplaceSync(const nsAString& aText, ErrorResult& aRv);
int32_t AddRule(const nsAString& aSelector, const nsAString& aBlock,
const dom::Optional<uint32_t>& aIndex,
nsIPrincipal& aSubjectPrincipal, ErrorResult& aRv);
@@ -192,6 +195,13 @@ public:
inline void DidDirty();
inline void AssertHasUniqueInner();
bool IsConstructed() const { return mConstructed; }
nsIDocument* ConstructorDocument() const { return mConstructorDocument; }
void AddAdopter(nsIDocument* aDocument);
void RemoveAdopter(nsIDocument* aDocument);
void AddAdopter(dom::ShadowRoot* aShadowRoot);
void RemoveAdopter(dom::ShadowRoot* aShadowRoot);
private:
// Get a handle to the various stylesheet bits which live on the 'inner' for
// gecko stylesheets.
@@ -205,6 +215,14 @@ private:
bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv);
void SetConstructed() { mConstructed = true; }
void SetConstructorDocument(nsIDocument* aDocument)
{
MOZ_ASSERT(IsConstructed());
mConstructorDocument = aDocument;
}
bool IsModificationDisallowed() const { return mDisallowModification; }
protected:
// Return success if the subject principal subsumes the principal of our
// inner, error otherwise. This will also succeed if the subject has
@@ -212,10 +230,13 @@ protected:
// it will set the principal of the inner to the subject principal.
void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv);
void NotifyAdopterRuleChanged();
nsString mTitle;
nsIDocument* mDocument; // weak ref; parents maintain this for their children
RefPtr<nsIDocument> mConstructorDocument;
nsINode* mOwningNode; // weak ref
nsTArray<dom::ShadowRoot*> mAdopterShadowRoots; // weak; roots unadopt on unlink/destruction
// mParsingMode controls access to nonstandard style constructs that
// are not safe for use on the public Web but necessary in UA sheets
@@ -223,6 +244,9 @@ protected:
css::SheetParsingMode mParsingMode;
bool mDisabled;
bool mConstructed;
bool mDisallowModification;
uint32_t mAdoptionCount;
// mDocumentAssociationMode determines whether mDocument directly owns us (in
// the sense that if it's known-live then we're known-live). Always
+57 -13
View File
@@ -127,7 +127,9 @@ enum class SelectorParsingFlags {
eDisallowCombinators = 1 << 2,
eDisallowPseudoElements = 1 << 3,
eInheritNamespace = 1 << 4,
eForceEmptyList = 1 << 5
eForceEmptyList = 1 << 5,
eIsRelativeSelector = 1 << 6,
eInsideHas = 1 << 7
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorParsingFlags)
@@ -6452,6 +6454,28 @@ CSSParserImpl::ParseSelectorGroup(nsCSSSelectorList*& aList,
char16_t combinator = 0;
nsAutoPtr<nsCSSSelectorList> list(new nsCSSSelectorList());
if (aFlags & SelectorParsingFlags::eIsRelativeSelector) {
// A relative selector is evaluated as though it begins with an internal
// anchor and a combinator. This must not use :scope: an explicit :scope
// in the argument continues to refer to the caller's scoping root.
// If the combinator is omitted, it is a descendant combinator.
nsCSSSelector* anchor = list->AddSelector(char16_t(0));
anchor->AddPseudoClass(CSSPseudoClassType::mozHasRelativeAnchor);
list->mIsRelativeSelector = true;
combinator = char16_t(' ');
if (GetToken(true)) {
if (mToken.mType == eCSSToken_Symbol &&
(mToken.mSymbol == '+' ||
mToken.mSymbol == '>' ||
mToken.mSymbol == '~')) {
combinator = mToken.mSymbol;
} else {
UngetToken();
}
}
}
for (;;) {
if (!ParseSelector(list, combinator, aFlags)) {
return false;
@@ -7125,6 +7149,9 @@ CSSParserImpl::ParsePseudoSelector(int32_t& aDataMask,
if (aFlags & SelectorParsingFlags::eDisallowCombinators) {
flags |= SelectorParsingFlags::eDisallowCombinators;
}
if (aFlags & SelectorParsingFlags::eInsideHas) {
flags |= SelectorParsingFlags::eInsideHas;
}
if (aFlags & SelectorParsingFlags::eForceEmptyList ||
forceEmptyList) {
flags |= SelectorParsingFlags::eForceEmptyList;
@@ -7570,7 +7597,15 @@ CSSParserImpl::ParsePseudoClassWithSelectorListArg(nsCSSSelector& aSelector,
bool isSingleSelector =
nsCSSPseudoClasses::HasSingleSelectorArg(aType);
if (nsCSSPseudoClasses::HasForgivingSelectorListArg(aType)) {
if (aType == CSSPseudoClassType::has) {
// :has() takes an unforgiving <relative-selector-list>, cannot be nested,
// and cannot contain pseudo-elements.
if (aFlags & SelectorParsingFlags::eInsideHas) {
return eSelectorParsingStatus_Error;
}
aFlags |= SelectorParsingFlags::eIsRelativeSelector |
SelectorParsingFlags::eInsideHas;
} else if (nsCSSPseudoClasses::HasForgivingSelectorListArg(aType)) {
aFlags |= SelectorParsingFlags::eIsForgiving;
} else if (isSingleSelector || aType == CSSPseudoClassType::mozAny) {
aFlags |= SelectorParsingFlags::eDisallowCombinators;
@@ -13419,23 +13454,26 @@ bool
CSSParserImpl::ParseAspectRatioRatio(nsCSSValue& aValue)
{
nsCSSValue width;
if (!ParseNonNegativeNumber(width)) {
if (!ParseSingleTokenNonNegativeVariant(width,
VARIANT_NUMBER | VARIANT_CALC,
nullptr)) {
return false;
}
float w = width.GetFloatValue();
float h = 1.0f;
nsCSSValue height;
height.SetFloatValue(1.0f, eCSSUnit_Number);
if (ExpectSymbol('/', true)) {
nsCSSValue height;
if (!ParseNonNegativeNumber(height)) {
if (!ParseSingleTokenNonNegativeVariant(height,
VARIANT_NUMBER | VARIANT_CALC,
nullptr)) {
return false;
}
h = height.GetFloatValue();
}
// Degenerate ratios behave as auto in layout.
aValue.SetFloatValue(w == 0.0f || h == 0.0f ? 0.0f : w / h,
eCSSUnit_Number);
// Keep both components: the computed value is a pair of numbers, and
// degenerate ratios still serialize as ratios even though they behave as
// auto during layout.
aValue.SetPairValue(width, height);
return true;
}
@@ -13458,9 +13496,15 @@ CSSParserImpl::ParseAspectRatio(nsCSSValue& aValue)
if (hasRatio) {
if (!hasAuto) {
// The grammar is "auto || <ratio>", so auto may appear after the ratio.
ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
hasAuto = ParseSingleTokenVariant(autoValue, VARIANT_AUTO, nullptr);
}
if (hasAuto) {
nsCSSValue combined;
combined.SetPairValue(autoValue, ratioValue);
aValue = combined;
} else {
aValue = ratioValue;
}
aValue = ratioValue;
return true;
}
+2 -2
View File
@@ -479,8 +479,8 @@ CSS_PROP_POSITION(
"",
0,
nullptr,
offsetof(nsStylePosition, mAspectRatio),
eStyleAnimType_None)
CSS_PROP_NO_OFFSET,
eStyleAnimType_Custom)
CSS_PROP_DISPLAY(
backface-visibility,
backface_visibility,
+3
View File
@@ -77,6 +77,9 @@ CSS_PSEUDO_CLASS(is, ":is", 0, "layout.css.is-where-pseudo.enabled")
CSS_PSEUDO_CLASS(matches, ":matches", 0, "layout.css.is-where-pseudo.enabled")
CSS_PSEUDO_CLASS(any, ":any", 0, "layout.css.is-where-pseudo.enabled")
CSS_PSEUDO_CLASS(where, ":where", 0, "layout.css.is-where-pseudo.enabled")
CSS_PSEUDO_CLASS(has, ":has", 0, "")
CSS_PSEUDO_CLASS(mozHasRelativeAnchor, ":-moz-has-relative-anchor",
CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "")
CSS_PSEUDO_CLASS(firstChild, ":first-child", 0, "")
CSS_PSEUDO_CLASS(firstNode, ":-moz-first-node", 0, "")
+1
View File
@@ -159,6 +159,7 @@ bool
nsCSSPseudoClasses::HasSelectorListArg(Type aType)
{
return HasForgivingSelectorListArg(aType) ||
aType == Type::has ||
aType == Type::negation ||
aType == Type::mozAny ||
aType == Type::mozAnyPrivate ||
+171 -27
View File
@@ -887,20 +887,34 @@ nsCSSRuleUtils::SelectorMatches(Element* aElement,
}
break;
case CSSPseudoClassType::is:
case CSSPseudoClassType::matches:
case CSSPseudoClassType::any:
case CSSPseudoClassType::where: {
case CSSPseudoClassType::is:
case CSSPseudoClassType::matches:
case CSSPseudoClassType::any:
case CSSPseudoClassType::where: {
if (!SelectorListMatches(aElement,
pseudoClass,
aNodeMatchContext,
aTreeMatchContext,
true)) {
return false;
}
} break;
case CSSPseudoClassType::mozAny: {
}
} break;
case CSSPseudoClassType::has: {
if (!RelativeSelectorListMatches(aElement,
pseudoClass->u.mSelectorList,
aTreeMatchContext)) {
return false;
}
} break;
case CSSPseudoClassType::mozHasRelativeAnchor:
if (aElement != aTreeMatchContext.mRelativeSelectorAnchor) {
return false;
}
break;
case CSSPseudoClassType::mozAny: {
// XXX: For compatibility, we retain :-moz-any()'s original behavior,
// which is to be unforgiving and reject complex selectors in
// its selector list argument.
@@ -1626,8 +1640,10 @@ nsCSSRuleUtils::SelectorListMatches(Element* aElement,
SelectorMatchesTreeFlags selectorTreeFlags = SelectorMatchesTreeFlags(0);
// Try to look for the closest ancestor link element if we're processing
// the selector list argument of a pseudo-class, but only if for a new style context (see SelectorMatches).
if (!aNodeMatchContext.mIsRelevantLink && aTreeMatchContext.mForStyling &&
(aSelectorFlags & SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
if (!aNodeMatchContext.mIsRelevantLink &&
!aTreeMatchContext.mRelativeSelectorAnchor &&
aTreeMatchContext.mForStyling &&
(aSelectorFlags & SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
selectorTreeFlags = eLookForRelevantLink;
}
@@ -1644,23 +1660,151 @@ nsCSSRuleUtils::SelectorListMatches(Element* aElement,
}
/* static */ bool
nsCSSRuleUtils::SelectorListMatches(Element* aElement,
nsPseudoClassList* aList,
NodeMatchContext& aNodeMatchContext,
TreeMatchContext& aTreeMatchContext,
bool aIsForgiving,
bool aPreventComplexSelectors)
{
return SelectorListMatches(aElement,
aList->u.mSelectorList,
aNodeMatchContext,
aTreeMatchContext,
SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT,
aIsForgiving,
aPreventComplexSelectors);
}
// TreeMatchContext and AncestorFilter out of line methods
nsCSSRuleUtils::SelectorListMatches(Element* aElement,
nsPseudoClassList* aList,
NodeMatchContext& aNodeMatchContext,
TreeMatchContext& aTreeMatchContext,
bool aIsForgiving,
bool aPreventComplexSelectors)
{
return SelectorListMatches(aElement,
aList->u.mSelectorList,
aNodeMatchContext,
aTreeMatchContext,
SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT,
aIsForgiving,
aPreventComplexSelectors);
}
static inline bool
matchesCandidate(Element* aCandidate,
nsCSSSelectorList* aRelativeSelector,
TreeMatchContext& aTreeMatchContext)
{
AutoRestore<Element*> styleScopeRestorer(
aTreeMatchContext.mCurrentStyleScope);
// A candidate inspected by :has() is never the relevant link for the
// anchor being styled. Treating it as relevant would allow
// :has(:visited) to expose link history through an ancestor.
NodeMatchContext nodeContext(EventStates(), false);
nsCSSSelector* selector = aRelativeSelector->mSelectors;
if (!nsCSSRuleUtils::SelectorMatches(
aCandidate,
selector,
nodeContext,
aTreeMatchContext,
SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
return false;
}
return !selector->mNext ||
nsCSSRuleUtils::SelectorMatchesTree(
aCandidate,
selector->mNext,
aTreeMatchContext,
SelectorMatchesTreeFlags(0));
}
static inline bool
matchesSubtree(nsIContent* aRoot,
nsCSSSelectorList* aRelativeSelector,
TreeMatchContext& aTreeMatchContext)
{
for (nsIContent* node = aRoot;
node;
node = node->GetNextNode(aRoot)) {
if (node->IsElement() &&
matchesCandidate(node->AsElement(),
aRelativeSelector,
aTreeMatchContext)) {
return true;
}
}
return false;
}
/* static */ bool
nsCSSRuleUtils::RelativeSelectorListMatches(
Element* aAnchor,
nsCSSSelectorList* aList,
TreeMatchContext& aTreeMatchContext)
{
MOZ_ASSERT(aAnchor);
MOZ_ASSERT(aList);
// :has() reverses the usual direction of selector invalidation. The
// restyle manager uses these conservative markers to promote changes in the
// anchor's descendants, or in following sibling subtrees, back to a subtree
// that contains the anchor.
if (aTreeMatchContext.mForStyling) {
aAnchor->SetProperty(nsGkAtoms::hasSelectorDependency,
reinterpret_cast<void*>(1));
nsIContent* parent = aAnchor->GetParent();
if (parent) {
parent->SetProperty(nsGkAtoms::hasSelectorDependency,
reinterpret_cast<void*>(1));
}
}
AutoRestore<Element*> relativeAnchorRestorer(
aTreeMatchContext.mRelativeSelectorAnchor);
aTreeMatchContext.mRelativeSelectorAnchor = aAnchor;
for (nsCSSSelectorList* relative = aList;
relative;
relative = relative->mNext) {
MOZ_ASSERT(relative->mIsRelativeSelector);
MOZ_ASSERT(relative->mSelectors && relative->mSelectors->mNext);
// Find the compound immediately to the right of the implicit internal
// anchor. This selector representation stores a combinator on its
// left-hand selector, so the anchor owns the leading combinator.
nsCSSSelector* leftmost = relative->mSelectors;
while (leftmost->mNext && leftmost->mNext->mNext) {
leftmost = leftmost->mNext;
}
MOZ_ASSERT(leftmost->mNext);
switch (leftmost->mNext->mOperator) {
// Even for a leading adjacent-sibling combinator, a later combinator in
// the relative selector can move the rightmost matching element into a
// subsequent sibling subtree (for example, :has(+ .a + .b)). Search
// every following subtree and let the full selector enforce the exact
// leading relationship to the anchor.
case char16_t('+'):
case char16_t('~'):
for (Element* sibling = aAnchor->GetNextElementSibling();
sibling;
sibling = sibling->GetNextElementSibling()) {
if (matchesSubtree(sibling, relative, aTreeMatchContext)) {
return true;
}
}
break;
case char16_t('>'):
case char16_t(' '):
for (nsIContent* node = aAnchor->GetFirstChild();
node;
node = node->GetNextNode(aAnchor)) {
if (node->IsElement() &&
matchesCandidate(node->AsElement(),
relative,
aTreeMatchContext)) {
return true;
}
}
break;
default:
MOZ_ASSERT(false, "unexpected relative selector combinator");
break;
}
}
return false;
}
// TreeMatchContext and AncestorFilter out of line methods
void
TreeMatchContext::InitAncestors(Element* aElement)
{
+12 -7
View File
@@ -69,13 +69,18 @@ struct nsCSSRuleUtils
bool aIsForgiving = false,
bool aPreventComplexSelectors = false);
static bool SelectorListMatches(Element* aElement,
nsPseudoClassList* aList,
NodeMatchContext& aNodeMatchContext,
TreeMatchContext& aTreeMatchContext,
bool aIsForgiving = false,
bool aPreventComplexSelectors = false);
static bool SelectorListMatches(Element* aElement,
nsPseudoClassList* aList,
NodeMatchContext& aNodeMatchContext,
TreeMatchContext& aTreeMatchContext,
bool aIsForgiving = false,
bool aPreventComplexSelectors = false);
static bool RelativeSelectorListMatches(
Element* aAnchor,
nsCSSSelectorList* aList,
TreeMatchContext& aTreeMatchContext);
#ifdef DEBUG
static bool HasPseudoClassSelectorArgsWithCombinators(
nsCSSSelector* aSelector);
+14
View File
@@ -2972,6 +2972,20 @@ nsCSSValuePair::AppendToString(nsCSSPropertyID aProperty,
nsAString& aResult,
nsCSSValue::Serialization aSerialization) const
{
if (aProperty == eCSSProperty_aspect_ratio) {
if (mXValue.GetUnit() == eCSSUnit_Auto) {
mXValue.AppendToString(aProperty, aResult, aSerialization);
aResult.Append(char16_t(' '));
mYValue.AppendToString(aProperty, aResult, aSerialization);
return;
}
mXValue.AppendToString(aProperty, aResult, aSerialization);
aResult.AppendLiteral(" / ");
mYValue.AppendToString(aProperty, aResult, aSerialization);
return;
}
mXValue.AppendToString(aProperty, aResult, aSerialization);
if (mYValue.GetUnit() != eCSSUnit_Null) {
aResult.Append(char16_t(' '));
+8 -4
View File
@@ -968,13 +968,17 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetAspectRatio()
{
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
float ratio = StylePosition()->mAspectRatio;
if (ratio == 0.0f) {
const StyleAspectRatio& ratio = StylePosition()->mAspectRatio;
if (!ratio.HasRatio()) {
val->SetIdent(eCSSKeyword_auto);
} else {
nsAutoString ratioString;
nsStyleUtil::AppendCSSNumber(ratio, ratioString);
ratioString.AppendLiteral(" / 1");
if (ratio.mAuto) {
ratioString.AppendLiteral("auto ");
}
nsStyleUtil::AppendCSSNumber(ratio.mWidth, ratioString);
ratioString.AppendLiteral(" / ");
nsStyleUtil::AppendCSSNumber(ratio.mHeight, ratioString);
val->SetString(ratioString);
}
return val.forget();
+47 -8
View File
@@ -9607,15 +9607,54 @@ nsRuleNode::ComputePositionData(void* aStartStruct,
SETCOORD_UNSET_INITIAL,
aContext, mPresContext, conditions);
// aspect-ratio: auto | <ratio>
// aspect-ratio: auto || <ratio>
const nsCSSValue* aspectRatio = aRuleData->ValueForAspectRatio();
if (aspectRatio->GetUnit() == eCSSUnit_Auto) {
pos->mAspectRatio = 0.0f;
} else {
SetFactor(*aspectRatio,
pos->mAspectRatio, conditions,
parentPos->mAspectRatio, 0.0f,
SETFCT_UNSET_INITIAL | SETFCT_POSITIVE | SETFCT_NONE);
switch (aspectRatio->GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_Inherit:
conditions.SetUncacheable();
pos->mAspectRatio = parentPos->mAspectRatio;
break;
case eCSSUnit_Auto:
case eCSSUnit_Initial:
case eCSSUnit_Unset:
case eCSSUnit_Revert:
case eCSSUnit_RevertLayer:
pos->mAspectRatio = StyleAspectRatio();
break;
case eCSSUnit_Number:
// Animation normalizes a ratio to <number> / 1 when both components
// would otherwise compare equal and the pair is collapsed.
pos->mAspectRatio =
StyleAspectRatio(aspectRatio->GetFloatValue(), 1.0f, false);
break;
case eCSSUnit_Pair: {
const nsCSSValuePair* ratio = &aspectRatio->GetPairValue();
bool hasAuto = ratio->mXValue.GetUnit() == eCSSUnit_Auto;
if (hasAuto) {
MOZ_ASSERT(ratio->mYValue.GetUnit() == eCSSUnit_Pair,
"auto must be followed by a ratio");
ratio = &ratio->mYValue.GetPairValue();
}
float width = 0.0f;
float height = 0.0f;
SetFactor(ratio->mXValue, width, conditions, 0.0f, 0.0f,
SETFCT_POSITIVE);
SetFactor(ratio->mYValue, height, conditions, 0.0f, 0.0f,
SETFCT_POSITIVE);
pos->mAspectRatio = StyleAspectRatio(width, height, hasAuto);
break;
}
default:
MOZ_ASSERT_UNREACHABLE("unexpected aspect-ratio unit");
break;
}
// box-sizing: enum, inherit, initial
+6
View File
@@ -449,6 +449,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
, mCurrentStyleScope(nullptr)
, mIsTopmostScope(false)
, mForAssignedSlot(false)
, mRelativeSelectorAnchor(nullptr)
{
if (aMatchVisited != eNeverMatchVisited) {
nsILoadContext* loadContext = mDocument->GetLoadContext();
@@ -466,6 +467,11 @@ struct MOZ_STACK_CLASS TreeMatchContext {
nsRuleWalker::eRelevantLinkUnvisited,
aDocument)
{}
// The anchor used by the implementation-only leftmost compound of a
// relative selector. This is deliberately separate from mScopes: an
// explicit :scope inside :has() still refers to the API/style scope.
mozilla::dom::Element* mRelativeSelectorAnchor;
};
struct MOZ_STACK_CLASS RuleProcessorData {
+1 -24
View File
@@ -8,6 +8,7 @@
#ifndef nsStyleCoord_h___
#define nsStyleCoord_h___
#include "mozilla/LogicalTypes.h"
#include "nsCoord.h"
#include "nsStyleConsts.h"
#include "nsTArray.h"
@@ -17,30 +18,6 @@ namespace mozilla {
class WritingMode;
// Logical axis, edge, side and corner constants for use in various places.
enum LogicalAxis {
eLogicalAxisBlock = 0x0,
eLogicalAxisInline = 0x1
};
enum LogicalEdge {
eLogicalEdgeStart = 0x0,
eLogicalEdgeEnd = 0x1
};
enum LogicalSide {
eLogicalSideBStart = (eLogicalAxisBlock << 1) | eLogicalEdgeStart, // 0x0
eLogicalSideBEnd = (eLogicalAxisBlock << 1) | eLogicalEdgeEnd, // 0x1
eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart, // 0x2
eLogicalSideIEnd = (eLogicalAxisInline << 1) | eLogicalEdgeEnd // 0x3
};
enum LogicalCorner
{
eLogicalCornerBStartIStart = 0,
eLogicalCornerBStartIEnd = 1,
eLogicalCornerBEndIEnd = 2,
eLogicalCornerBEndIStart = 3
};
} // namespace mozilla
enum nsStyleUnit : uint8_t {
+1 -1
View File
@@ -1372,7 +1372,7 @@ nsStylePosition::nsStylePosition(nsPresContext* aContext)
, mGridAutoColumnsMax(eStyleUnit_Auto)
, mGridAutoRowsMin(eStyleUnit_Auto)
, mGridAutoRowsMax(eStyleUnit_Auto)
, mAspectRatio(0.0f)
, mAspectRatio()
, mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW)
, mBoxSizing(StyleBoxSizing::Content)
, mAlignContent(NS_STYLE_ALIGN_NORMAL)
+48 -1
View File
@@ -34,6 +34,7 @@
#include "imgRequestProxy.h"
#include "Orientation.h"
#include "CounterStyleManager.h"
#include <cmath>
#include <cstddef> // offsetof()
#include <utility>
#include "X11UndefineNone.h"
@@ -1679,6 +1680,52 @@ struct nsStyleGridTemplate
}
};
namespace mozilla {
struct StyleAspectRatio {
StyleAspectRatio()
: mWidth(0.0f)
, mHeight(1.0f)
, mAuto(true)
, mHasRatio(false)
{}
StyleAspectRatio(float aWidth, float aHeight, bool aAuto)
: mWidth(aWidth)
, mHeight(aHeight)
, mAuto(aAuto)
, mHasRatio(true)
{}
bool HasRatio() const { return mHasRatio; }
bool HasUsableRatio() const {
return mHasRatio &&
mWidth != 0.0f &&
mHeight != 0.0f &&
std::isfinite(mWidth) &&
std::isfinite(mHeight);
}
bool operator==(const StyleAspectRatio& aOther) const {
return mWidth == aOther.mWidth &&
mHeight == aOther.mHeight &&
mAuto == aOther.mAuto &&
mHasRatio == aOther.mHasRatio;
}
bool operator!=(const StyleAspectRatio& aOther) const {
return !(*this == aOther);
}
float mWidth;
float mHeight;
bool mAuto;
bool mHasRatio;
};
} // namespace mozilla
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition
{
explicit nsStylePosition(nsPresContext* aContext);
@@ -1743,7 +1790,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition
nsStyleCoord mGridAutoColumnsMax; // [reset] coord, percent, enum, calc, flex
nsStyleCoord mGridAutoRowsMin; // [reset] coord, percent, enum, calc, flex
nsStyleCoord mGridAutoRowsMax; // [reset] coord, percent, enum, calc, flex
float mAspectRatio; // [reset] float
mozilla::StyleAspectRatio mAspectRatio; // [reset]
uint8_t mGridAutoFlow; // [reset] enumerated. See nsStyleConsts.h
mozilla::StyleBoxSizing mBoxSizing; // [reset] see nsStyleConsts.h
+1
View File
@@ -250,6 +250,7 @@ support-files = redundant_font_download.sjs
[test_rule_insertion.html]
[test_rule_serialization.html]
[test_rules_out_of_sheets.html]
[test_has_pseudo_class.html]
[test_selectors.html]
[test_selectors_on_anonymous_content.html]
[test_setPropertyWithNull.html]
+24 -2
View File
@@ -1172,8 +1172,30 @@ var gCSSProperties = {
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: ["auto"],
other_values: ["1", "2"],
invalid_values: ["none", "-1", "1px", "1 / -1", "1 /", "auto auto"],
other_values: [
"1",
"2",
"3 / 2",
"0",
"0 / 1",
"1 / 0",
"auto 16 / 9",
"16 / 9 auto",
"calc(1 + 1)",
"calc(6) / calc(4)",
],
invalid_values: [
"none",
"-1",
"1px",
"1 / -1",
"1 /",
"auto auto",
"1 1",
"1 / 1 / 1",
"auto 1 auto",
"infinity",
],
},
"-moz-border-bottom-colors": {
domProp: "MozBorderBottomColors",
@@ -4,29 +4,76 @@
<title>Test CSS aspect-ratio property</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<style>
@keyframes aspect-ratio-interpolation {
from { aspect-ratio: 1; }
to { aspect-ratio: 4; }
}
#animated-ratio {
animation: aspect-ratio-interpolation 100s linear -50s paused;
}
</style>
</head>
<body>
<div id="container" style="position:absolute; left:0; top:0; width:120px;">
<div id="ratio" style="width:120px; aspect-ratio:3 / 2;"></div>
<div id="bare-ratio" style="width:120px; aspect-ratio:2;"></div>
<div id="wrapper" style="position:relative; width:120px; aspect-ratio:1 / 1;">
<div style="position:absolute; inset:0;"></div>
</div>
<div id="zero-ratio" style="width:120px; aspect-ratio:0;"></div>
<div id="border-box-ratio"
style="box-sizing:border-box; width:120px; padding:10px;
border:10px solid; aspect-ratio:2;"></div>
<div id="content-box-ratio"
style="box-sizing:content-box; width:120px; padding:10px;
border:10px solid; aspect-ratio:2;"></div>
<div id="auto-border-box-ratio"
style="box-sizing:border-box; width:120px; padding:10px;
border:10px solid; aspect-ratio:auto 2;"></div>
<div id="animated-ratio" style="width:120px;"></div>
<img id="override-natural-ratio"
style="display:block; width:120px; height:auto; aspect-ratio:1;"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='20'%3E%3C/svg%3E">
<img id="use-natural-ratio"
style="display:block; width:120px; height:auto; aspect-ratio:auto 1;"
src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='20'%3E%3C/svg%3E">
</div>
<pre id="test">
<script type="application/javascript">
ok(CSS.supports("aspect-ratio", "1 / 1"),
"aspect-ratio accepts ratio syntax");
ok(CSS.supports("aspect-ratio", "2"),
"aspect-ratio accepts a ratio with an omitted denominator");
ok(CSS.supports("aspect-ratio", "auto"),
"aspect-ratio accepts auto");
ok(CSS.supports("aspect-ratio", "auto 16 / 9"),
"aspect-ratio accepts auto plus ratio");
ok(CSS.supports("aspect-ratio", "16 / 9 auto"),
"aspect-ratio accepts ratio plus auto");
ok(CSS.supports("aspect-ratio", "calc(1 + 1)"),
"aspect-ratio accepts math functions as numbers");
ok(CSS.supports("aspect-ratio", "0 / 1"),
"aspect-ratio accepts degenerate ratios");
ok(!CSS.supports("aspect-ratio", "1px"),
"aspect-ratio rejects lengths");
ok(!CSS.supports("aspect-ratio", "-1"),
"aspect-ratio rejects negative numbers");
ok(!CSS.supports("aspect-ratio", "auto auto"),
"aspect-ratio rejects duplicate auto keywords");
var ratio = document.getElementById("ratio");
is(ratio.getBoundingClientRect().height, 80,
"aspect-ratio computes an automatic block size from inline size");
is(getComputedStyle(ratio).aspectRatio, "3 / 2",
"computed aspect-ratio preserves both ratio components");
var bareRatio = document.getElementById("bare-ratio");
is(bareRatio.getBoundingClientRect().height, 60,
"a bare number computes an automatic block size");
is(getComputedStyle(bareRatio).aspectRatio, "2 / 1",
"a ratio with an omitted denominator serializes with denominator 1");
var wrapper = document.getElementById("wrapper");
is(wrapper.getBoundingClientRect().height, 120,
@@ -35,6 +82,66 @@ is(wrapper.getBoundingClientRect().height, 120,
is(getComputedStyle(wrapper).aspectRatio, "1 / 1",
"computed aspect-ratio exposes a ratio value");
var zeroRatio = document.getElementById("zero-ratio");
is(zeroRatio.getBoundingClientRect().height, 0,
"a degenerate ratio behaves as auto during layout");
is(getComputedStyle(zeroRatio).aspectRatio, "0 / 1",
"a degenerate ratio remains a ratio in the computed value");
is(document.getElementById("border-box-ratio").getBoundingClientRect().height,
60, "a specified ratio honors border-box sizing");
is(document.getElementById("content-box-ratio").getBoundingClientRect().height,
100, "a specified ratio honors content-box sizing");
is(document.getElementById("auto-border-box-ratio")
.getBoundingClientRect().height,
80, "the fallback in auto plus ratio always uses the content box");
var animatedRatio = document.getElementById("animated-ratio");
is(animatedRatio.getBoundingClientRect().height, 60,
"aspect-ratio interpolation is logarithmic");
is(getComputedStyle(animatedRatio).aspectRatio, "2 / 1",
"an interpolated ratio is exposed as a pair of numbers");
var declaration = document.createElement("div").style;
declaration.aspectRatio = "3 / 2 auto";
is(declaration.aspectRatio, "auto 3 / 2",
"specified aspect-ratio serializes in canonical order");
SimpleTest.waitForExplicitFinish();
var images = [
document.getElementById("override-natural-ratio"),
document.getElementById("use-natural-ratio"),
];
var pendingImages = images.length;
function checkReplacedElements() {
is(images[0].getBoundingClientRect().height, 120,
"a ratio without auto overrides a replaced element's natural ratio");
is(images[1].getBoundingClientRect().height, 60,
"auto plus ratio uses a replaced element's natural ratio");
is(getComputedStyle(images[1]).aspectRatio, "auto 1 / 1",
"computed style preserves auto plus ratio");
SimpleTest.finish();
}
function imageReady() {
if (--pendingImages == 0) {
checkReplacedElements();
}
}
images.forEach(function(image) {
if (image.complete) {
imageReady();
} else {
image.addEventListener("load", imageReady);
image.addEventListener("error", function() {
ok(false, "test image should load");
imageReady();
});
}
});
</script>
</pre>
</body>
@@ -8,9 +8,13 @@
</head>
<body>
<pre id="test"></pre>
<div id="adopted-target"></div>
<div id="shadow-host"></div>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
let sheet;
try {
@@ -33,7 +37,130 @@ if (sheet) {
sheet.deleteRule(0);
is(sheet.cssRules.length, 0, "deleteRule should remove the rule");
is(sheet.replaceSync("#test { color: rgb(4, 5, 6); } p { margin-top: 1px; }"),
undefined, "replaceSync should return undefined");
is(sheet.cssRules.length, 2, "replaceSync should replace with parsed rules");
is(sheet.cssRules[0].selectorText, "#test",
"replaceSync should expose the first parsed rule");
is(sheet.cssRules[1].selectorText, "p",
"replaceSync should expose subsequent parsed rules");
sheet.replaceSync("@import url('neverending_stylesheet_load.sjs'); #test { color: rgb(7, 8, 9); }");
is(sheet.cssRules.length, 1, "replaceSync should remove @import rules");
is(sheet.cssRules[0].selectorText, "#test",
"replaceSync should keep non-import rules after removed imports");
sheet.replaceSync("}");
is(sheet.cssRules.length, 0,
"replaceSync should replace with an empty rule list when nothing parses");
try {
document.styleSheets[0].replaceSync("#test { color: rgb(10, 11, 12); }");
ok(false, "replaceSync should throw for non-constructed sheets");
} catch (e) {
is(e.name, "NotAllowedError",
"replaceSync should reject non-constructed sheets with NotAllowedError");
}
try {
sheet.insertRule("@import url('neverending_stylesheet_load.sjs');", 0);
ok(false, "insertRule should reject @import rules for constructed sheets");
} catch (e) {
is(e.name, "SyntaxError",
"insertRule should reject constructed-sheet @import rules with SyntaxError");
}
}
function colorFor(node) {
return getComputedStyle(node).color;
}
function runAdoptionTests() {
let target = document.getElementById("adopted-target");
let adopted = new CSSStyleSheet();
adopted.replaceSync("#adopted-target { color: rgb(12, 34, 56); }");
document.adoptedStyleSheets = [adopted];
is(document.adoptedStyleSheets.length, 1,
"document.adoptedStyleSheets should expose assigned sheets");
is(document.adoptedStyleSheets[0], adopted,
"document.adoptedStyleSheets should expose the same CSSStyleSheet object");
is(document.styleSheets.length, 1,
"document.styleSheets should not include adopted sheets");
is(colorFor(target), "rgb(12, 34, 56)",
"adopted document sheets should apply");
adopted.replaceSync("#adopted-target { color: rgb(20, 30, 40); }");
is(colorFor(target), "rgb(20, 30, 40)",
"mutating an adopted sheet should update document style");
let laterStyle = document.createElement("style");
laterStyle.textContent = "#adopted-target { color: rgb(1, 2, 3); }";
document.head.appendChild(laterStyle);
is(colorFor(target), "rgb(20, 30, 40)",
"adopted document sheets should cascade after ordinary document sheets");
try {
document.adoptedStyleSheets = [document.styleSheets[0]];
ok(false, "adopting a non-constructed sheet should throw");
} catch (e) {
is(e.name, "NotAllowedError",
"adopting a non-constructed sheet should throw NotAllowedError");
}
let iframe = document.createElement("iframe");
iframe.onload = function() {
let foreignSheet = new iframe.contentWindow.CSSStyleSheet();
try {
document.adoptedStyleSheets = [foreignSheet];
ok(false, "adopting a sheet from another document should throw");
} catch (e) {
is(e.name, "NotAllowedError",
"adopting a sheet from another document should throw NotAllowedError");
}
iframe.remove();
if ("attachShadow" in document.getElementById("shadow-host")) {
runShadowAdoptionTests();
} else {
finishAdoptionTests();
}
};
document.body.appendChild(iframe);
}
function runShadowAdoptionTests() {
let host = document.getElementById("shadow-host");
let root = host.attachShadow({ mode: "open" });
root.innerHTML = "<style>span { color: rgb(1, 2, 3); }</style><span>shadow</span>";
let shadowSheet = new CSSStyleSheet();
shadowSheet.replaceSync("span { color: rgb(45, 67, 89); }");
root.adoptedStyleSheets = [shadowSheet];
let span = root.querySelector("span");
is(root.adoptedStyleSheets.length, 1,
"shadowRoot.adoptedStyleSheets should expose assigned sheets");
is(root.styleSheets.length, 1,
"shadowRoot.styleSheets should not include adopted sheets");
is(colorFor(span), "rgb(45, 67, 89)",
"adopted shadow sheets should apply after ordinary shadow sheets");
shadowSheet.replaceSync("span { color: rgb(90, 80, 70); }");
is(colorFor(span), "rgb(90, 80, 70)",
"mutating an adopted shadow sheet should update shadow style");
finishAdoptionTests();
}
function finishAdoptionTests() {
document.adoptedStyleSheets = [];
SimpleTest.finish();
}
runAdoptionTests();
</script>
</body>
</html>
@@ -0,0 +1,167 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>CSS :has() relational pseudo-class</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<style id="has-styles">
.dynamic,
.structural,
.sibling-anchor,
.state-anchor,
.empty-anchor {
color: rgb(0, 0, 255);
}
.dynamic:has(.watched),
.structural:has(> .inserted),
.sibling-anchor:has(+ .sibling-target.active),
.state-anchor:has(input:checked),
.empty-anchor:has(> :empty) {
color: rgb(255, 0, 0);
}
.specificity.other {
color: rgb(0, 0, 255);
}
/* The maximum specificity in the list is used even when that list item
does not match. */
.specificity:has(.specificity-child, #does-not-exist) {
color: rgb(255, 0, 0);
}
</style>
</head>
<body>
<div id="descendant-anchor">
<div class="descendant"><span class="deep"></span></div>
<p class="direct"></p>
</div>
<div id="nonmatching-anchor"><div class="descendant"></div></div>
<h2 id="sibling-query-anchor"></h2>
<p id="adjacent"><span class="inside-adjacent"></span></p>
<p class="later-sibling"></p>
<div id="dynamic" class="dynamic"><span id="dynamic-child"></span></div>
<div id="structural" class="structural"></div>
<div id="sibling-anchor" class="sibling-anchor"></div>
<div id="sibling-target" class="sibling-target"></div>
<div id="state-anchor" class="state-anchor"><input id="checkbox" type="checkbox"></div>
<div id="empty-anchor" class="empty-anchor"><span id="empty-child"></span></div>
<div id="specificity" class="specificity other"><span class="specificity-child"></span></div>
<div id="explicit-outer" class="explicit-outer">
<div id="explicit-scope"><span class="scope-result"></span></div>
</div>
<div id="visited-anchor"><a href=""></a></div>
<script>
"use strict";
const blue = "rgb(0, 0, 255)";
const red = "rgb(255, 0, 0)";
function color(id) {
return getComputedStyle(document.getElementById(id)).color;
}
function syntaxError(selector) {
let threw = false;
try {
document.querySelector(selector);
} catch (error) {
threw = error.name === "SyntaxError";
}
ok(threw, selector + " is rejected as an invalid selector");
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
is(document.querySelector("div:has(.deep)").id,
"descendant-anchor",
"implicit descendant relative selector matches");
is(document.querySelector("div:has(> .direct)").id,
"descendant-anchor",
"leading child combinator matches");
is(document.querySelector("h2:has(+ p .inside-adjacent)").id,
"sibling-query-anchor",
"adjacent sibling subtree matches");
is(document.querySelector("h2:has(+ p + .later-sibling)").id,
"sibling-query-anchor",
"later combinators can move beyond the adjacent sibling subtree");
is(document.querySelector("h2:has(~ .later-sibling)").id,
"sibling-query-anchor",
"subsequent sibling matches");
ok(!document.getElementById("nonmatching-anchor").matches(":has(.deep)"),
"a descendant of the wrong compound does not match");
is(document.querySelector(".inside-adjacent").closest("p:has(.inside-adjacent)").id,
"adjacent",
":has() works through closest()");
syntaxError("div:has()");
syntaxError("div:has(.deep, :definitely-unknown)");
syntaxError("div:has(:has(.deep))");
syntaxError("div:has(::before)");
let explicitScope = document.getElementById("explicit-scope");
is(explicitScope.querySelectorAll(":has(:scope)").length, 0,
"explicit :scope is distinct from the implicit relative anchor");
is(explicitScope.querySelectorAll(
".explicit-outer:has(:scope) .scope-result").length, 1,
"explicit :scope inside :has() refers to the query scoping root");
ok(document.documentElement.matches(":has(:is(:has(*), body))"),
"an invalid nested :has() branch is discarded by a forgiving :is()");
ok(!document.documentElement.matches(":has(:is(:has(*)))"),
"a forgiving list containing only invalid nested :has() matches nothing");
ok(!document.getElementById("visited-anchor").matches(":has(:visited)"),
":visited does not expose history through :has()");
ok(document.getElementById("visited-anchor").matches(":has(:link)"),
":link remains usable inside :has()");
let sheet = document.getElementById("has-styles").sheet;
let index = sheet.insertRule("article:has(> img, + aside .note) {}", sheet.cssRules.length);
is(sheet.cssRules[index].selectorText,
"article:has(> img, + aside .note)",
"relative selector list serialization does not expose the implicit anchor");
sheet.deleteRule(index);
is(color("specificity"), red,
":has() uses the most specific selector in its complete argument list");
is(color("dynamic"), blue, "descendant attribute dependency starts unmatched");
document.getElementById("dynamic-child").classList.add("watched");
is(color("dynamic"), red, "descendant attribute change makes :has() match");
document.getElementById("dynamic-child").classList.remove("watched");
is(color("dynamic"), blue, "descendant attribute change makes :has() stop matching");
is(color("structural"), blue, "child dependency starts unmatched");
let inserted = document.createElement("span");
inserted.className = "inserted";
document.getElementById("structural").appendChild(inserted);
is(color("structural"), red, "child insertion makes :has() match");
inserted.remove();
is(color("structural"), blue, "child removal makes :has() stop matching");
is(color("sibling-anchor"), blue, "sibling dependency starts unmatched");
document.getElementById("sibling-target").classList.add("active");
is(color("sibling-anchor"), red, "following sibling attribute change invalidates anchor");
document.getElementById("sibling-target").classList.remove("active");
is(color("sibling-anchor"), blue, "following sibling can stop matching dynamically");
is(color("state-anchor"), blue, "state dependency starts unmatched");
document.getElementById("checkbox").checked = true;
is(color("state-anchor"), red, "descendant state change invalidates anchor");
document.getElementById("checkbox").checked = false;
is(color("state-anchor"), blue, "descendant state can stop matching dynamically");
is(color("empty-anchor"), red, ":empty inside :has() initially matches");
document.getElementById("empty-child").appendChild(document.createTextNode("text"));
is(color("empty-anchor"), blue, "text insertion invalidates :empty inside :has()");
SimpleTest.finish();
});
</script>
</body>
</html>
+1 -1
View File
@@ -344,7 +344,7 @@ nsSVGOuterSVGFrame::ComputeSize(nsRenderingContext *aRenderingContext,
}
return ComputeSizeWithIntrinsicDimensions(aRenderingContext, aWM,
intrinsicSize, GetIntrinsicRatio(),
intrinsicSize, GetAspectRatio(),
cbSize, aMargin, aBorder, aPadding,
aFlags);
}
+7
View File
@@ -49,6 +49,13 @@
#include "config_unix_ppc.h"
#elif defined(__sparcv9) || defined(__sparcv9__)
#include "config_unix_sparc64.h"
#elif defined(__mips__)
// This is needed to avoid enabling x86 assembly on 64-bit MIPS.
#include "config_unix32.h"
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#undef HAVE_BIGENDIAN
#define HAVE_BIGENDIAN 1
#endif
#elif defined(__loongarch64)
#include "config_unix_loongarch64.h"
#else
+4
View File
@@ -6,5 +6,9 @@
#else
#define AV_HAVE_BIGENDIAN 0
#endif
#if defined(__mips__)
#define AV_HAVE_FAST_UNALIGNED 0
#else
#define AV_HAVE_FAST_UNALIGNED 1
#endif
#endif /* AVUTIL_AVCONFIG_H */
@@ -16,6 +16,30 @@
#if HAVE_MMI
/*
* Clang's integrated assembler uses the prefixed spellings below, while
* GNU as names the same Loongson MMI instructions xor/and/or/dsrl/srl.
* Define GNU as aliases so the inline assembly works with either toolchain.
*/
#if defined(__GNUC__) && !defined(__clang__)
__asm__(
".macro pxor dst, src1, src2\n\t"
"xor \\dst, \\src1, \\src2\n\t"
".endm\n\t"
".macro pand dst, src1, src2\n\t"
"and \\dst, \\src1, \\src2\n\t"
".endm\n\t"
".macro por dst, src1, src2\n\t"
"or \\dst, \\src1, \\src2\n\t"
".endm\n\t"
".macro ssrld dst, src1, src2\n\t"
"dsrl \\dst, \\src1, \\src2\n\t"
".endm\n\t"
".macro ssrlw dst, src1, src2\n\t"
"srl \\dst, \\src1, \\src2\n\t"
".endm\n\t");
#endif
#if HAVE_MIPS64
#define mips_reg int64_t
#define MMI_ADDU(reg1, reg2, reg3) \
-6
View File
@@ -1358,12 +1358,6 @@ pref("network.notify.IPv6", false);
pref("network.notify.IPv6", true);
#endif
// Transmit UDP busy-work to the LAN when anticipating low latency
// network reads and on wifi to mitigate 802.11 Power Save Polling delays
pref("network.tickle-wifi.enabled", false);
pref("network.tickle-wifi.duration", 400);
pref("network.tickle-wifi.delay", 16);
// Turn off interprocess security checks. Needed to run xpcshell tests.
pref("network.disable.ipc.security", false);
Loaded 100 of 135 files, more files were not shown because too many files have changed in this diff. Show more