Compare commits

..
69 Commits
Author SHA1 Message Date
Moonchild 44d17e4ee7 Replace strnlen with memchr. See code comment. 2026-08-15 10:19:41 +02:00
Moonchild 26cc7c3126 Revert "Refactor string utils in MFBT."
This reverts commit cea1b66ba5.
2026-08-15 09:49:46 +02:00
Moonchild cea1b66ba5 Refactor string utils in MFBT.
This adds an Apple carveout for strnlen for OS X < 10.7 and renames the
ToString.h header to StringUtils.h to better reflect the more generic
collection of functions in it, instead of a 1-file-1-method header.
2026-08-13 16:42:35 +02: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
106 changed files with 1790 additions and 1035 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',
]
+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")
+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"]
+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 :
+15 -7
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);
+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.
+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);
+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);
}
/*
+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;
}
+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
+80
View File
@@ -1987,6 +1987,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;
+16
View File
@@ -26,6 +26,8 @@ StyleSheet::StyleSheet(css::SheetParsingMode aParsingMode)
, mOwningNode(nullptr)
, mParsingMode(aParsingMode)
, mDisabled(false)
, mConstructed(false)
, mDisallowModification(false)
, mDocumentAssociationMode(NotOwnedByDocument)
{
}
@@ -38,6 +40,8 @@ StyleSheet::StyleSheet(const StyleSheet& aCopy,
, mOwningNode(aOwningNodeToUse)
, mParsingMode(aCopy.mParsingMode)
, mDisabled(aCopy.mDisabled)
, mConstructed(aCopy.mConstructed)
, mDisallowModification(false)
// 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)
@@ -254,6 +258,7 @@ StyleSheet::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
sheet->SetURIs(documentURI, nullptr, baseURI);
sheet->SetPrincipal(principal);
sheet->SetComplete();
sheet->SetConstructed();
return sheet.forget();
}
@@ -290,6 +295,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,
+7
View File
@@ -160,6 +160,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);
@@ -205,6 +206,10 @@ private:
bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
ErrorResult& aRv);
bool IsConstructed() const { return mConstructed; }
void SetConstructed() { mConstructed = true; }
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
@@ -223,6 +228,8 @@ protected:
css::SheetParsingMode mParsingMode;
bool mDisabled;
bool mConstructed;
bool mDisallowModification;
// 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>
@@ -33,6 +33,31 @@ 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");
}
}
</script>
</body>
@@ -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);
}
-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);
-277
View File
@@ -1,277 +0,0 @@
/* -*- 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/. */
#include "Tickler.h"
#ifdef MOZ_USE_WIFI_TICKLER
#include "nsComponentManagerUtils.h"
#include "nsIPrefBranch.h"
#include "nsIPrefService.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "prnetdb.h"
#include "mozilla/jni/Utils.h"
#include "GeneratedJNIWrappers.h"
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS(Tickler, nsISupportsWeakReference, Tickler)
Tickler::Tickler()
: mLock("Tickler::mLock")
, mActive(false)
, mCanceled(false)
, mEnabled(false)
, mDelay(16)
, mDuration(TimeDuration::FromMilliseconds(400))
, mFD(nullptr)
{
MOZ_ASSERT(NS_IsMainThread());
}
Tickler::~Tickler()
{
// non main thread uses of the tickler should hold weak
// references to it if they must hold a reference at all
MOZ_ASSERT(NS_IsMainThread());
if (mThread) {
mThread->AsyncShutdown();
mThread = nullptr;
}
if (mTimer)
mTimer->Cancel();
if (mFD)
PR_Close(mFD);
}
nsresult
Tickler::Init()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mTimer);
MOZ_ASSERT(!mActive);
MOZ_ASSERT(!mThread);
MOZ_ASSERT(!mFD);
if (jni::IsAvailable()) {
java::GeckoAppShell::EnableNetworkNotifications();
}
mFD = PR_OpenUDPSocket(PR_AF_INET);
if (!mFD)
return NS_ERROR_FAILURE;
// make sure new socket has a ttl of 1
// failure is not fatal.
PRSocketOptionData opt;
opt.option = PR_SockOpt_IpTimeToLive;
opt.value.ip_ttl = 1;
PR_SetSocketOption(mFD, &opt);
nsresult rv = NS_NewNamedThread("wifi tickler",
getter_AddRefs(mThread));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsITimer> tmpTimer(do_CreateInstance(NS_TIMER_CONTRACTID, &rv));
if (NS_FAILED(rv))
return rv;
rv = tmpTimer->SetTarget(mThread);
if (NS_FAILED(rv))
return rv;
mTimer.swap(tmpTimer);
mAddr.inet.family = PR_AF_INET;
mAddr.inet.port = PR_htons (4886);
mAddr.inet.ip = 0;
return NS_OK;
}
void Tickler::Tickle()
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(mThread);
mLastTickle = TimeStamp::Now();
if (!mActive)
MaybeStartTickler();
}
void Tickler::PostCheckTickler()
{
mLock.AssertCurrentThreadOwns();
mThread->Dispatch(NewRunnableMethod(this, &Tickler::CheckTickler),
NS_DISPATCH_NORMAL);
return;
}
void Tickler::MaybeStartTicklerUnlocked()
{
MutexAutoLock lock(mLock);
MaybeStartTickler();
}
void Tickler::MaybeStartTickler()
{
mLock.AssertCurrentThreadOwns();
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(
NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked));
return;
}
if (!mPrefs)
mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (mPrefs) {
int32_t val;
bool boolVal;
if (NS_SUCCEEDED(mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal)))
mEnabled = boolVal;
if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) {
if (val < 1)
val = 1;
if (val > 100000)
val = 100000;
mDuration = TimeDuration::FromMilliseconds(val);
}
if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) {
if (val < 1)
val = 1;
if (val > 1000)
val = 1000;
mDelay = static_cast<uint32_t>(val);
}
}
PostCheckTickler();
}
void Tickler::CheckTickler()
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(mThread == NS_GetCurrentThread());
bool shouldRun = (!mCanceled) &&
((TimeStamp::Now() - mLastTickle) <= mDuration);
if ((shouldRun && mActive) || (!shouldRun && !mActive))
return; // no change in state
if (mActive)
StopTickler();
else
StartTickler();
}
void Tickler::Cancel()
{
MutexAutoLock lock(mLock);
MOZ_ASSERT(NS_IsMainThread());
mCanceled = true;
if (mThread)
PostCheckTickler();
}
void Tickler::StopTickler()
{
mLock.AssertCurrentThreadOwns();
MOZ_ASSERT(mThread == NS_GetCurrentThread());
MOZ_ASSERT(mTimer);
MOZ_ASSERT(mActive);
mTimer->Cancel();
mActive = false;
}
class TicklerTimer final : public nsITimerCallback
{
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSITIMERCALLBACK
TicklerTimer(Tickler *aTickler)
{
mTickler = do_GetWeakReference(aTickler);
}
private:
~TicklerTimer() {}
nsWeakPtr mTickler;
};
void Tickler::StartTickler()
{
mLock.AssertCurrentThreadOwns();
MOZ_ASSERT(mThread == NS_GetCurrentThread());
MOZ_ASSERT(!mActive);
MOZ_ASSERT(mTimer);
if (NS_SUCCEEDED(mTimer->InitWithCallback(new TicklerTimer(this),
mEnabled ? mDelay : 1000,
nsITimer::TYPE_REPEATING_SLACK)))
mActive = true;
}
// argument should be in network byte order
void Tickler::SetIPV4Address(uint32_t address)
{
mAddr.inet.ip = address;
}
// argument should be in network byte order
void Tickler::SetIPV4Port(uint16_t port)
{
mAddr.inet.port = port;
}
NS_IMPL_ISUPPORTS(TicklerTimer, nsITimerCallback)
NS_IMETHODIMP TicklerTimer::Notify(nsITimer *timer)
{
RefPtr<Tickler> tickler = do_QueryReferent(mTickler);
if (!tickler)
return NS_ERROR_FAILURE;
MutexAutoLock lock(tickler->mLock);
if (!tickler->mFD) {
tickler->StopTickler();
return NS_ERROR_FAILURE;
}
if (tickler->mCanceled ||
((TimeStamp::Now() - tickler->mLastTickle) > tickler->mDuration)) {
tickler->StopTickler();
return NS_OK;
}
if (!tickler->mEnabled)
return NS_OK;
PR_SendTo(tickler->mFD, "", 0, 0, &tickler->mAddr, 0);
return NS_OK;
}
} // namespace mozilla::net
} // namespace mozilla
#else // not defined MOZ_USE_WIFI_TICKLER
namespace mozilla {
namespace net {
NS_IMPL_ISUPPORTS0(Tickler)
} // namespace net
} // namespace mozilla
#endif // defined MOZ_USE_WIFI_TICKLER
-127
View File
@@ -1,127 +0,0 @@
/* -*- 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_net_Tickler_h
#define mozilla_net_Tickler_h
// The tickler sends a regular 0 byte UDP heartbeat out to a
// particular address for a short time after it has been touched. This
// is used on some mobile wifi chipsets to mitigate Power Save Polling
// (PSP) Mode when we are anticipating a response packet
// soon. Typically PSP adds 100ms of latency to a read event because
// the packet delivery is not triggered until the 802.11 beacon is
// delivered to the host (100ms is the standard Access Point
// configuration for the beacon interval.) Requesting a frequent
// transmission and getting a CTS frame from the AP at least that
// frequently allows for low latency receives when we have reason to
// expect them (e.g a SYN-ACK).
//
// The tickler is used to allow RTT based phases of web transport to
// complete quickly when on wifi - ARP, DNS, TCP handshake, SSL
// handshake, HTTP headers, and the TCP slow start phase. The
// transaction is given up to 400 miliseconds by default to get
// through those phases before the tickler is disabled.
//
// The tickler only applies to wifi on mobile right now. Hopefully it
// can also be restricted to particular handset models in the future.
#include "mozilla/Attributes.h"
#include "nsISupports.h"
#include <stdint.h>
#ifdef MOZ_USE_WIFI_TICKLER
#include "mozilla/Mutex.h"
#include "mozilla/TimeStamp.h"
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "nsIThread.h"
#include "nsITimer.h"
#include "nsWeakReference.h"
#include "prio.h"
class nsIPrefBranch;
#endif
namespace mozilla {
namespace net {
#ifdef MOZ_USE_WIFI_TICKLER
// 8f769ed6-207c-4af9-9f7e-9e832da3754e
#define NS_TICKLER_IID \
{ 0x8f769ed6, 0x207c, 0x4af9, \
{ 0x9f, 0x7e, 0x9e, 0x83, 0x2d, 0xa3, 0x75, 0x4e } }
class Tickler final : public nsSupportsWeakReference
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECLARE_STATIC_IID_ACCESSOR(NS_TICKLER_IID)
// These methods are main thread only
Tickler();
void Cancel();
nsresult Init();
void SetIPV4Address(uint32_t address);
void SetIPV4Port(uint16_t port);
// Tickle the tickler to (re-)start the activity.
// May call from any thread
void Tickle();
private:
~Tickler();
friend class TicklerTimer;
Mutex mLock;
nsCOMPtr<nsIThread> mThread;
nsCOMPtr<nsITimer> mTimer;
nsCOMPtr<nsIPrefBranch> mPrefs;
bool mActive;
bool mCanceled;
bool mEnabled;
uint32_t mDelay;
TimeDuration mDuration;
PRFileDesc* mFD;
TimeStamp mLastTickle;
PRNetAddr mAddr;
// These functions may be called from any thread
void PostCheckTickler();
void MaybeStartTickler();
void MaybeStartTicklerUnlocked();
// Tickler thread only
void CheckTickler();
void StartTickler();
void StopTickler();
};
NS_DEFINE_STATIC_IID_ACCESSOR(Tickler, NS_TICKLER_IID)
#else // not defined MOZ_USE_WIFI_TICKLER
class Tickler final : public nsISupports
{
~Tickler() { }
public:
NS_DECL_THREADSAFE_ISUPPORTS
Tickler() { }
nsresult Init() { return NS_ERROR_NOT_IMPLEMENTED; }
void Cancel() { }
void SetIPV4Address(uint32_t) { };
void SetIPV4Port(uint16_t) { }
void Tickle() { }
};
#endif // defined MOZ_USE_WIFI_TICKLER
} // namespace net
} // namespace mozilla
#endif // mozilla_net_Tickler_h
-1
View File
@@ -245,7 +245,6 @@ UNIFIED_SOURCES += [
'SimpleBuffer.cpp',
'StreamingProtocolService.cpp',
'ThrottleQueue.cpp',
'Tickler.cpp',
'TLSServerSocket.cpp',
]
+13 -3
View File
@@ -481,7 +481,12 @@ NS_IMETHODIMP CacheEntry::OnFileReady(nsresult aResult, bool aIsNew)
NS_IMETHODIMP CacheEntry::OnFileDoomed(nsresult aResult)
{
if (mDoomCallback) {
bool doomCallback = false;
{
mozilla::MutexAutoLock lock(mLock);
doomCallback = bool(mDoomCallback);
}
if (doomCallback) {
RefPtr<DoomCallbackRunnable> event =
new DoomCallbackRunnable(this, aResult);
NS_DispatchToMainThread(event);
@@ -1738,8 +1743,13 @@ void CacheEntry::DoomFile()
}
}
// Always posts to the main thread.
OnFileDoomed(rv);
// mLock is already held in the caller; dispatch directly
// instead of calling OnFileDoomed() which would deadlock when
// re-acquiring the lock.
if (mDoomCallback) {
RefPtr<DoomCallbackRunnable> event = new DoomCallbackRunnable(this, rv);
NS_DispatchToMainThread(event);
}
}
void CacheEntry::RemoveForcedValidity()
+2 -48
View File
@@ -29,9 +29,6 @@ uint32_t CacheObserver::sUseNewCache = kDefaultUseNewCache;
static int32_t const kAutoDeleteCacheVersion = -1; // Auto-delete off by default
static int32_t sAutoDeleteCacheVersion = kAutoDeleteCacheVersion;
static int32_t const kDefaultHalfLifeExperiment = -1; // Disabled
int32_t CacheObserver::sHalfLifeExperiment = kDefaultHalfLifeExperiment;
static float const kDefaultHalfLifeHours = 1.0F; // 1 hour
float CacheObserver::sHalfLifeHours = kDefaultHalfLifeHours;
@@ -189,51 +186,8 @@ CacheObserver::AttachToPreferences()
"browser.cache.disk.parent_directory", NS_GET_IID(nsIFile),
getter_AddRefs(mCacheParentDirectoryOverride));
// First check the default value. If it is at -1, the experient
// is turned off. If it is at 0, then use the user pref value
// instead.
sHalfLifeExperiment = mozilla::Preferences::GetDefaultInt(
"browser.cache.frecency_experiment", kDefaultHalfLifeExperiment);
if (sHalfLifeExperiment == 0) {
// Default preferences indicate we want to run the experiment,
// hence read the user value.
sHalfLifeExperiment = mozilla::Preferences::GetInt(
"browser.cache.frecency_experiment", sHalfLifeExperiment);
}
if (sHalfLifeExperiment == 0) {
// The experiment has not yet been initialized but is engaged, do
// the initialization now.
srand(time(NULL));
sHalfLifeExperiment = (rand() % 4) + 1;
// Store the experiemnt value, since we need it not to change between
// browser sessions.
mozilla::Preferences::SetInt(
"browser.cache.frecency_experiment", sHalfLifeExperiment);
}
switch (sHalfLifeExperiment) {
case 1: // The experiment is engaged
sHalfLifeHours = 0.083F; // ~5 mintues
break;
case 2:
sHalfLifeHours = 0.25F; // 15 mintues
break;
case 3:
sHalfLifeHours = 1.0F;
break;
case 4:
sHalfLifeHours = 6.0F;
break;
case -1:
default: // The experiment is off or broken
sHalfLifeExperiment = -1;
sHalfLifeHours = std::max(0.01F, std::min(1440.0F, mozilla::Preferences::GetFloat(
"browser.cache.frecency_half_life_hours", kDefaultHalfLifeHours)));
break;
}
sHalfLifeHours = std::max(0.01F, std::min(1440.0F, mozilla::Preferences::GetFloat(
"browser.cache.frecency_half_life_hours", kDefaultHalfLifeHours)));
mozilla::Preferences::AddBoolVarCache(
&sSanitizeOnShutdown, "privacy.sanitize.sanitizeOnShutdown", kDefaultSanitizeOnShutdown);
-3
View File
@@ -57,8 +57,6 @@ class CacheObserver : public nsIObserver
{ return sCompressionLevel; }
static uint32_t HalfLifeSeconds()
{ return sHalfLifeHours * 60.0F * 60.0F; }
static int32_t HalfLifeExperiment()
{ return sHalfLifeExperiment; }
static bool ClearCacheOnShutdown()
{ return sSanitizeOnShutdown && sClearCacheOnShutdown; }
static void ParentDirOverride(nsIFile ** aDir);
@@ -95,7 +93,6 @@ private:
static uint32_t sMaxDiskPriorityChunksMemoryUsage;
static uint32_t sCompressionLevel;
static float sHalfLifeHours;
static int32_t sHalfLifeExperiment;
static bool sSanitizeOnShutdown;
static bool sClearCacheOnShutdown;
static Atomic<uint32_t, Relaxed> sMaxShutdownIOLag;
-48
View File
@@ -34,7 +34,6 @@
#include "nsAlgorithm.h"
#include "ASpdySession.h"
#include "EventTokenBucket.h"
#include "Tickler.h"
#include "nsIXULAppInfo.h"
#include "nsICookieService.h"
#include "nsIObserverService.h"
@@ -396,9 +395,6 @@ nsHttpHandler::Init()
}
MakeNewRequestTokenBucket();
mWifiTickler = new Tickler();
if (NS_FAILED(mWifiTickler->Init()))
mWifiTickler = nullptr;
nsCOMPtr<nsIParentalControlsService> pc = do_CreateInstance("@mozilla.org/parental-controls-service;1");
if (pc) {
@@ -2124,8 +2120,6 @@ nsHttpHandler::Observe(nsISupports *subject,
// clear cache of all authentication credentials.
mAuthCache.ClearAll();
mPrivateAuthCache.ClearAll();
if (mWifiTickler)
mWifiTickler->Cancel();
// Inform nsIOService that network is tearing down.
gIOService->SetHttpHandlerAlreadyShutingDown();
@@ -2338,48 +2332,6 @@ nsHttpHandler::SpeculativeAnonymousConnect2(nsIURI *aURI,
return SpeculativeConnectInternal(aURI, aPrincipal, aCallbacks, true);
}
void
nsHttpHandler::TickleWifi(nsIInterfaceRequestor *cb)
{
if (!cb || !mWifiTickler)
return;
// If B2G requires a similar mechanism nsINetworkManager, currently only avail
// on B2G, contains the necessary information on wifi and gateway
nsCOMPtr<nsIDOMWindow> domWindow = do_GetInterface(cb);
nsCOMPtr<nsPIDOMWindowOuter> piWindow = do_QueryInterface(domWindow);
if (!piWindow)
return;
nsCOMPtr<nsIDOMNavigator> domNavigator = piWindow->GetNavigator();
nsCOMPtr<nsIMozNavigatorNetwork> networkNavigator =
do_QueryInterface(domNavigator);
if (!networkNavigator)
return;
nsCOMPtr<nsINetworkProperties> networkProperties;
networkNavigator->GetProperties(getter_AddRefs(networkProperties));
if (!networkProperties)
return;
uint32_t gwAddress;
bool isWifi;
nsresult rv;
rv = networkProperties->GetDhcpGateway(&gwAddress);
if (NS_SUCCEEDED(rv))
rv = networkProperties->GetIsWifi(&isWifi);
if (NS_FAILED(rv))
return;
if (!gwAddress || !isWifi)
return;
mWifiTickler->SetIPV4Address(gwAddress);
mWifiTickler->Tickle();
}
//-----------------------------------------------------------------------------
// nsHttpsHandler implementation
//-----------------------------------------------------------------------------
-6
View File
@@ -39,7 +39,6 @@ extern Atomic<PRThread*, Relaxed> gSocketThread;
class ATokenBucketEvent;
class EventTokenBucket;
class Tickler;
class nsHttpConnection;
class nsHttpConnectionInfo;
class nsHttpTransaction;
@@ -245,7 +244,6 @@ public:
nsIInterfaceRequestor *callbacks,
uint32_t caps = 0)
{
TickleWifi(callbacks);
RefPtr<nsHttpConnectionInfo> clone = ci->Clone();
return mConnMgr->SpeculativeConnect(clone, callbacks, caps);
}
@@ -645,10 +643,6 @@ public:
}
}
private:
RefPtr<Tickler> mWifiTickler;
void TickleWifi(nsIInterfaceRequestor *cb);
private:
nsresult SpeculativeConnectInternal(nsIURI *aURI,
nsIPrincipal *aPrincipal,
+8
View File
@@ -318,6 +318,14 @@ sctp_mark_non_revokable(struct sctp_association *asoc, uint32_t tsn)
return;
}
SCTP_CALC_TSN_TO_GAP(gap, tsn, asoc->mapping_array_base_tsn);
if (gap >= (uint32_t)(asoc->mapping_array_size << 3)) {
/*
* The TSN falls outside the mapping window, e.g. a control
* queued before a large FORWARD-TSN moved the window past it.
* It has no bit in either map, so there is nothing to mark.
*/
return;
}
in_r = SCTP_IS_TSN_PRESENT(asoc->mapping_array, gap);
in_nr = SCTP_IS_TSN_PRESENT(asoc->nr_mapping_array, gap);
KASSERT(in_r || in_nr, ("%s: Things are really messed up now", __func__));
+27 -17
View File
@@ -258,6 +258,8 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
struct sctp_init *init;
struct sctp_association *asoc;
struct sctp_nets *lnet;
struct sctp_stream_reset_list *strrst, *nstrrst;
struct sctp_queued_to_read *sq, *nsq;
unsigned int i;
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -358,6 +360,27 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb)
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
/* open the requested streams */
/*
* Flush inbound stream state carrying stream ids validated against the
* old streamincnt before strmin is reallocated below; otherwise a later
* drain of pending_reply_queue could index the new (smaller) strmin out
* of bounds.
*/
TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) {
TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp);
SCTP_FREE(strrst, SCTP_M_STRESET);
}
TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) {
TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next);
if (sq->data) {
sctp_m_freem(sq->data);
sq->data = NULL;
}
sctp_free_remote_addr(sq->whoFrom);
sq->whoFrom = NULL;
sq->stcb = NULL;
sctp_free_a_readq(stcb, sq);
}
if (asoc->strmin != NULL) {
/* Free the old ones */
for (i = 0; i < asoc->streamincnt; i++) {
@@ -1475,8 +1498,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
struct sctp_asconf_addr *aparam, *naparam;
struct sctp_asconf_ack *aack, *naack;
struct sctp_tmit_chunk *chk, *nchk;
struct sctp_stream_reset_list *strrst, *nstrrst;
struct sctp_queued_to_read *sq, *nsq;
struct sctp_nets *net;
struct mbuf *op_err;
int init_offset, initack_offset, i;
@@ -1989,21 +2010,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
stcb->asoc.strmout[i].sid = i;
stcb->asoc.strmout[i].last_msg_incomplete = 0;
}
TAILQ_FOREACH_SAFE(strrst, &asoc->resetHead, next_resp, nstrrst) {
TAILQ_REMOVE(&asoc->resetHead, strrst, next_resp);
SCTP_FREE(strrst, SCTP_M_STRESET);
}
TAILQ_FOREACH_SAFE(sq, &asoc->pending_reply_queue, next, nsq) {
TAILQ_REMOVE(&asoc->pending_reply_queue, sq, next);
if (sq->data) {
sctp_m_freem(sq->data);
sq->data = NULL;
}
sctp_free_remote_addr(sq->whoFrom);
sq->whoFrom = NULL;
sq->stcb = NULL;
sctp_free_a_readq(stcb, sq);
}
/*
* resetHead and pending_reply_queue are flushed by
* sctp_process_init() below, where strmin is reallocated.
*/
TAILQ_FOREACH_SAFE(chk, &asoc->control_send_queue, sctp_next, nchk) {
TAILQ_REMOVE(&asoc->control_send_queue, chk, sctp_next);
if (chk->data) {
+6 -1
View File
@@ -690,6 +690,9 @@ nsHtml5TreeOperation::CreateMathMLElement(nsIAtom* aName,
void
nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
{
if (aNode->SubtreeRoot() != aParent->SubtreeRoot()) {
return;
}
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
nsCOMPtr<nsIDOMHTMLImageElement> domImageElement = do_QueryInterface(aNode);
// NS_ASSERTION(formControl, "Form-associated element did not implement nsIFormControl.");
@@ -704,7 +707,9 @@ nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
RefPtr<dom::HTMLImageElement> imageElement =
static_cast<dom::HTMLImageElement*>(domImageElement.get());
MOZ_ASSERT(imageElement);
imageElement->SetForm(formElement);
if (!imageElement->GetForm()) {
imageElement->SetForm(formElement);
}
}
}
@@ -79,7 +79,7 @@ class FasterMakeBackend(CommonBackend, PartialBackend):
.add_pattern_symlink(
prefix,
f.full_path[len(prefix):],
mozpath.join(obj.install_target, path))
path)
else:
self._install_manifests[obj.install_target].add_symlink(
f.full_path,
+1 -1
View File
@@ -481,7 +481,7 @@ class PreprocessedFile(BaseFile):
pp = Preprocessor(defines=self.defines, marker=self.marker)
pp.setSilenceDirectiveWarnings(self.silence_missing_directive_warnings)
with open(self.path, 'rU') as input:
with open(self.path, 'r') as input:
pp.processFile(input=input, output=dest, depfile=deps_out)
dest.close()
+10
View File
@@ -8,6 +8,7 @@
#include "secasn1.h"
#include "secitem.h"
#include <stdarg.h>
#include <limits.h>
#include "secerr.h"
#include "certi.h"
@@ -652,9 +653,18 @@ CERT_DecodeAVAValue(const SECItem *derAVAValue)
}
if (convert != conv_none) {
if (avaValue.len > UINT_MAX / 3) {
PORT_DestroyCheapArena(&tmpArena);
PORT_SetError(SEC_ERROR_INVALID_AVA);
return NULL;
}
unsigned int utf8ValLen = avaValue.len * 3;
unsigned char *utf8Val =
(unsigned char *)PORT_ArenaZAlloc(&tmpArena.arena, utf8ValLen);
if (!utf8Val) {
PORT_DestroyCheapArena(&tmpArena);
return NULL;
}
switch (convert) {
case conv_ucs4:
+8
View File
@@ -6,6 +6,8 @@
* certhtml.c --- convert a cert to html
*/
#include <limits.h>
#include "seccomon.h"
#include "secitem.h"
#include "sechash.h"
@@ -14,6 +16,7 @@
#include "secder.h"
#include "prprf.h"
#include "secport.h"
#include "secerr.h"
#include "secasn1.h"
#include "pk11func.h"
@@ -32,6 +35,11 @@ CERT_Hexify(SECItem *i, int do_colon)
return PORT_Strdup("00");
}
if (i->len > UINT_MAX / 3) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
rv = o = (char *)PORT_Alloc(i->len * 3);
if (!rv)
return rv;
+7
View File
@@ -696,6 +696,13 @@ SECKEY_ECParamsToKeySize(const SECItem *encodedParams)
/* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID),
* followed by the length of the curve oid and the curve oid.
*/
if (!encodedParams || !encodedParams->data ||
encodedParams->len < 2 ||
encodedParams->data[0] != SEC_ASN1_OBJECT_ID ||
(unsigned)encodedParams->data[1] > encodedParams->len - 2) {
PORT_SetError(SEC_ERROR_BAD_DER);
return 0;
}
oid.len = encodedParams->data[1];
oid.data = encodedParams->data + 2;
if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)
+5
View File
@@ -248,6 +248,11 @@ nss_cert_type_from_ck_attrib(CK_ATTRIBUTE_PTR attrib)
/* default to PKIX */
return NSSCertificateType_PKIX;
}
/* The token controls ulValueLen; reject any size that cannot hold a
* full CK_CERTIFICATE_TYPE to avoid an out-of-bounds heap read. */
if (attrib->ulValueLen != sizeof(CK_CERTIFICATE_TYPE)) {
return NSSCertificateType_Unknown;
}
ckCertType = *((CK_ULONG *)attrib->pValue);
switch (ckCertType) {
case CKC_X_509:
+2 -2
View File
@@ -22,10 +22,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.90.12.0 (UXP)" _NSS_CUSTOMIZED
#define NSS_VERSION "3.90.13.0 (UXP)" _NSS_CUSTOMIZED
#define NSS_VMAJOR 3
#define NSS_VMINOR 90
#define NSS_VPATCH 12
#define NSS_VPATCH 13
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
+9
View File
@@ -2269,11 +2269,20 @@ PK11_TraverseCertsForNicknameInSlot(SECItem *nickname, PK11SlotInfo *slot,
NSSCertificate **certs;
nssList *nameList = NULL;
nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
if (!nickname || !nickname->data || nickname->len == 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
token = PK11Slot_GetNSSToken(slot);
if (!token || !nssToken_IsPresent(token)) {
(void)nssToken_Destroy(token);
return SECSuccess;
}
if (!nickname || !nickname->data || nickname->len == 0) {
(void)nssToken_Destroy(token);
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (nickname->data[nickname->len - 1] != '\0') {
nick = nssUTF8_Create(NULL, nssStringType_UTF8String,
nickname->data, nickname->len);
+1 -1
View File
@@ -521,7 +521,7 @@ pk11_mergeSecretKey(PK11SlotInfo *targetSlot, PK11SlotInfo *sourceSlot,
goto done;
}
input.len = blockSize;
if (input.len == 0) {
if (input.len == 0 || input.len > sizeof(testString)) {
input.len = sizeof(testString);
}
while (targetKeyID != CK_INVALID_HANDLE) {
+6
View File
@@ -1214,6 +1214,12 @@ PK11_UnwrapPrivKey(PK11SlotInfo *slot, PK11SymKey *wrappingKey,
return NULL;
}
if (usageCount < 0 ||
usageCount > (int)(PR_ARRAY_SIZE(keyTemplate) - 8)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return NULL;
}
ck_id = PK11_MakeIDFromPubKey(idValue);
if (!ck_id) {
return NULL;
+4 -1
View File
@@ -371,7 +371,10 @@ PK11_GetWrapKey(PK11SlotInfo *slot, int wrap, CK_MECHANISM_TYPE type,
CK_OBJECT_HANDLE keyHandle;
PK11_EnterSlotMonitor(slot);
if (slot->series != series ||
/* refKeys is a fixed-size array; bounds-check wrap to match
* PK11_SetWrapKey. */
if (wrap < 0 || (size_t)wrap >= PR_ARRAY_SIZE(slot->refKeys) ||
slot->series != series ||
slot->refKeys[wrap] == CK_INVALID_HANDLE) {
PK11_ExitSlotMonitor(slot);
return NULL;
+2
View File
@@ -162,6 +162,7 @@ pk11_FreeSlotListStatic(PK11SlotList *list)
}
list->lock = NULL;
list->head = NULL;
list->tail = NULL;
}
/*
@@ -820,6 +821,7 @@ pk11_InitSlotListStatic(PK11SlotList *list)
{
list->lock = PZ_NewLock(nssILockList);
list->head = NULL;
list->tail = NULL;
}
/* initialize the system slotlists */
+28 -7
View File
@@ -1105,7 +1105,7 @@ p12u_DigestClose(void *arg, PRBool removeFile)
static int
p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
{
int toread = len;
int toread;
SEC_PKCS12DecoderContext *p12cxt = arg;
if (!buf || len == 0 || !p12cxt->buffer) {
@@ -1113,10 +1113,16 @@ p12u_DigestRead(void *arg, unsigned char *buf, unsigned long len)
return -1;
}
if ((p12cxt->filesize - p12cxt->currentpos) < (long)len) {
/* trying to read past the end of the buffer */
toread = p12cxt->filesize - p12cxt->currentpos;
/* Clamp `len` to the bytes left in the buffer. toread is positive here,
* so the comparison stays unsigned and `len` cannot wrap. */
toread = p12cxt->filesize - p12cxt->currentpos;
if (toread <= 0) {
return 0;
}
if (len < (unsigned long)toread) {
toread = (int)len;
}
memcpy(buf, (char *)p12cxt->buffer + p12cxt->currentpos, toread);
p12cxt->currentpos += toread;
return toread;
@@ -1131,10 +1137,18 @@ p12u_DigestWrite(void *arg, unsigned char *buf, unsigned long len)
return -1;
}
if (p12cxt->currentpos + (long)len > p12cxt->filesize) {
p12cxt->filesize = p12cxt->currentpos + len;
/* The buffer position counters are signed PRInt32. Reject any write
* whose length would not fit so that `len` cannot overflow or wrap them
* on LLP64 platforms where unsigned long is 32-bit (Win64). */
if (len > (unsigned long)(PR_INT32_MAX - p12cxt->currentpos)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return -1;
}
if (p12cxt->currentpos + (PRInt32)len > p12cxt->filesize) {
p12cxt->filesize = p12cxt->currentpos + (PRInt32)len;
} else {
p12cxt->filesize += len;
p12cxt->filesize += (PRInt32)len;
}
if (p12cxt->filesize > p12cxt->allocated) {
void *newbuffer;
@@ -1693,6 +1707,13 @@ sec_pkcs12_sanitize_nickname(PK11SlotInfo *slot, SECItem *nick)
slotName[slotNameLen] = '\0';
if (PORT_Strcmp(PK11_GetTokenName(slot), slotName) == 0) {
delimitlen = PORT_Strlen(delimit + 1);
if (delimitlen == 0) {
/* Nickname was exactly "TokenName:" with nothing after the
* prefix. Stripping it would yield an empty SECItem, which
* is not a useful nickname; leave the original in place. */
PORT_Free(slotName);
return;
}
PORT_Memmove(nickname, delimit + 1, delimitlen + 1);
nick->len = delimitlen;
}
+11 -6
View File
@@ -606,15 +606,20 @@ SEC_PKCS7DecryptContents(PLArenaPool *poolp,
rv = PK11_CipherOp((PK11Context *)cx, dest->data, (int *)(&dest->len),
(int)(src->len + 64), src->data, (int)src->len);
PK11_DestroyContext((PK11Context *)cx, PR_TRUE);
/* PK11_CipherOp may leave dest->len at 0; bail out before the padding
* check so dest->len - 1 does not underflow. */
if (rv != SECSuccess) {
goto loser;
}
bs = PK11_GetBlockSize(cryptoMechType, c_param);
if (bs) {
/* check for proper badding in block algorithms. this assumes
* RC2 cbc or a DES cbc variant. and the padding is thus defined
*/
if (((int)dest->data[dest->len - 1] <= bs) &&
((int)dest->data[dest->len - 1] > 0)) {
dest->len -= (int)dest->data[dest->len - 1];
/* Check for proper PKCS#7 padding: the last byte gives the number of
* pad bytes, which must be in [1, bs]. */
unsigned int pad = dest->data[dest->len - 1];
if ((dest->len >= (unsigned int)bs) &&
pad >= 1 && pad <= (unsigned int)bs) {
dest->len -= pad;
} else {
rv = SECFailure;
/* set an error ? */
+6
View File
@@ -773,6 +773,12 @@ sftk_ike1_appendix_b_prf(CK_SESSION_HANDLE hSession, const SFTKAttribute *inKey,
}
outKeySize = PR_ROUNDUP(keySize, macSize);
/* Reject if PR_ROUNDUP overflowed 32-bit unsigned arithmetic, which
* would yield an undersized allocation for the loop below. */
if (outKeySize < keySize) {
crv = CKR_KEY_SIZE_RANGE;
goto fail;
}
outKeyData = PORT_Alloc(outKeySize);
if (outKeyData == NULL) {
crv = CKR_HOST_MEMORY;
+2 -2
View File
@@ -17,10 +17,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.90.12.0 (UXP)" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.90.13.0 (UXP)" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 90
#define SOFTOKEN_VPATCH 12
#define SOFTOKEN_VPATCH 13
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
+6 -1
View File
@@ -722,7 +722,12 @@ ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
if (hook->writer) {
/* The writer writes directly into |buf|. Provide space that allows
* for the existing extensions, any tail, plus type and length. */
unsigned int space = buf->space - (buf->len + tail.len + 4);
unsigned int used = buf->len + tail.len + 4;
if (used > buf->space) {
PORT_SetError(SEC_ERROR_APPLICATION_CALLBACK_ERROR);
goto loser;
}
unsigned int space = buf->space - used;
append = (*hook->writer)(ss->fd, message,
buf->buf + buf->len + 4, &len, space,
hook->writerArg);
+6
View File
@@ -164,6 +164,12 @@ ssl_BeginClientHandshake(sslSocket *ss)
ss->sec.localCert = CERT_DupCertificate(sid->localCert);
} else {
ssl_UncacheSessionID(ss);
if (ss->sec.ci.sid == sid) {
/* sid aliases ss->sec.ci.sid (external cache); clear it so
* the socket cannot hold a dangling pointer if the
* ssl3_NewSessionID allocation below fails. */
ss->sec.ci.sid = NULL;
}
ssl_FreeSID(sid);
sid = NULL;
}
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff. Show more