diff --git a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js index 77b8c06882..72cc7f8980 100644 --- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js @@ -29,7 +29,7 @@ function* testTopLeft(inspector, view) { elementRulesNb: 4, firstLineRulesNb: 2, firstLetterRulesNb: 1, - selectionRulesNb: 0, + selectionRulesNb: 1, afterRulesNb: 1, beforeRulesNb: 2 } @@ -166,7 +166,7 @@ function* testParagraph(inspector, view) { elementRulesNb: 3, firstLineRulesNb: 1, firstLetterRulesNb: 1, - selectionRulesNb: 1, + selectionRulesNb: 2, beforeRulesNb: 0, afterRulesNb: 0 }); @@ -216,7 +216,7 @@ function* assertPseudoElementRulesNumbers(selector, inspector, view, ruleNbs) { firstLetterRules: elementStyle.rules.filter(rule => rule.pseudoElement === ":first-letter"), selectionRules: elementStyle.rules.filter(rule => - rule.pseudoElement === ":-moz-selection"), + rule.pseudoElement === ":selection"), beforeRules: elementStyle.rules.filter(rule => rule.pseudoElement === ":before"), afterRules: elementStyle.rules.filter(rule => diff --git a/devtools/shared/css/generated/properties-db.js b/devtools/shared/css/generated/properties-db.js index 316352771a..01358a033d 100644 --- a/devtools/shared/css/generated/properties-db.js +++ b/devtools/shared/css/generated/properties-db.js @@ -2872,6 +2872,7 @@ exports.CSS_PROPERTIES = { "box-shadow", "box-sizing", "caption-side", + "caret-color", "clear", "clip", "clip-path", @@ -5277,6 +5278,28 @@ exports.CSS_PROPERTIES = { "unset" ] }, + "caret-color": { + "isInherited": true, + "subproperties": [ + "caret-color" + ], + "supports": [ + 2 + ], + "values": [ + "COLOR", + "auto", + "currentColor", + "hsl", + "hsla", + "inherit", + "initial", + "rgb", + "rgba", + "transparent", + "unset" + ] + }, "clear": { "isInherited": false, "subproperties": [ @@ -9375,6 +9398,7 @@ exports.PSEUDO_ELEMENTS = [ ":backdrop", ":first-letter", ":first-line", + ":selection", ":-moz-selection", ":-moz-focus-inner", ":-moz-focus-outer", diff --git a/dom/base/ResizeObserverController.cpp b/dom/base/ResizeObserverController.cpp index acc401a5e2..d2162bb62e 100644 --- a/dom/base/ResizeObserverController.cpp +++ b/dom/base/ResizeObserverController.cpp @@ -15,7 +15,7 @@ namespace dom { void ResizeObserverNotificationHelper::WillRefresh(TimeStamp aTime) { - MOZ_ASSERT(mOwner, "Why is mOwner already dead when this RefreshObserver is still registered?"); + MOZ_DIAGNOSTIC_ASSERT(mOwner, "RefreshObserver should have been de-registered on time, but isn't."); if (mOwner) { mOwner->Notify(); } @@ -69,10 +69,8 @@ ResizeObserverNotificationHelper::Unregister() } nsRefreshDriver* refreshDriver = GetRefreshDriver(); - if (!refreshDriver) { - // We can't access RefreshDriver now. Just abort the Unregister(). - return; - } + MOZ_RELEASE_ASSERT(refreshDriver, + "We should not leave a dangling reference to the observer around"); refreshDriver->RemoveRefreshObserver(this, Flush_Display); mRegistered = false; @@ -81,9 +79,8 @@ ResizeObserverNotificationHelper::Unregister() void ResizeObserverNotificationHelper::Disconnect() { - Unregister(); - // Our owner is dying. Clear our pointer to it, in case we outlive it. - mOwner = nullptr; + MOZ_RELEASE_ASSERT(!mRegistered, "How can we die when registered?"); + MOZ_RELEASE_ASSERT(!mOwner, "Forgot to clear weak pointer?"); } ResizeObserverNotificationHelper::~ResizeObserverNotificationHelper() @@ -111,6 +108,10 @@ ResizeObserverController::AddResizeObserver(ResizeObserver* aObserver) mResizeObservers.AppendElement(aObserver); } +void ResizeObserverController::DetachFromDocument() { + mResizeObserverNotificationHelper->Unregister(); +} + void ResizeObserverController::Notify() { @@ -240,7 +241,10 @@ ResizeObserverController::GetShell() const ResizeObserverController::~ResizeObserverController() { - mResizeObserverNotificationHelper->Disconnect(); + MOZ_RELEASE_ASSERT( + !mResizeObserverNotificationHelper->IsRegistered(), + "Nothing else should keep a reference to our notification helper when we go away"); + mResizeObserverNotificationHelper->DetachFromOwner(); } } // namespace dom diff --git a/dom/base/ResizeObserverController.h b/dom/base/ResizeObserverController.h index 5d7912b438..01169112aa 100644 --- a/dom/base/ResizeObserverController.h +++ b/dom/base/ResizeObserverController.h @@ -41,6 +41,10 @@ public: void Disconnect(); + bool IsRegistered() const { return mRegistered; } + + void DetachFromOwner() { mOwner = nullptr; } + protected: virtual ~ResizeObserverNotificationHelper(); @@ -68,6 +72,7 @@ public: void Traverse(nsCycleCollectionTraversalCallback& aCb); void Unlink(); + void DetachFromDocument(); void AddResizeObserver(ResizeObserver* aObserver); /* diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index ce37c77b2c..0396848a99 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -3644,6 +3644,12 @@ nsDocument::DeleteShell() // objects for @font-face rules that came from the style set. RebuildUserFontSet(); + if (mResizeObserverController) { + // If the shell is going away, we need to remove any links to this document + // from the observer. + mResizeObserverController->DetachFromDocument(); + } + nsIPresShell* oldShell = mPresShell; mPresShell = nullptr; UpdateFrameRequestCallbackSchedulingState(oldShell); diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 7ddc2184b6..1226ef22e1 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -932,8 +932,12 @@ nsImageLoadingContent::LoadImage(nsIURI* aNewURI, MOZ_ASSERT(!req, "Shouldn't have non-null request here"); // If we don't have a current URI, we might as well store this URI so people // know what we tried (and failed) to load. - if (!mCurrentRequest) + if (!mCurrentRequest) { mCurrentURI = aNewURI; + if (mImageBlockingStatus == nsIContentPolicy::ACCEPT) { + mImageBlockingStatus = nsIContentPolicy::REJECT_REQUEST; + } + } FireEvent(NS_LITERAL_STRING("error")); FireEvent(NS_LITERAL_STRING("loadend")); diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 122875bb03..79bd5a0e39 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -708,10 +708,12 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest, // about races. if (mObserver) { + // Need to keep mObserver alive. + RefPtr observer = mObserver; if (NS_IsMainThread()) { - mObserver->OnDataAvailable(); + observer->OnDataAvailable(); } else { - RefPtr runnable = new DataAvailableRunnable(mObserver); + RefPtr runnable = new DataAvailableRunnable(observer); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -719,12 +721,15 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest, } } - uint32_t aRead; + // Explicitly initialized to 0 because in some cases nsStringInputStream may + // not write to aRead. + uint32_t aRead = 0; MOZ_ASSERT(mResponse); MOZ_ASSERT(mPipeOutputStream); // From "Main Fetch" step 17: SRI-part2. - if (mResponse->Type() != ResponseType::Error && + if (mResponse && + mResponse->Type() != ResponseType::Error && !mRequest->GetIntegrity().IsEmpty()) { MOZ_ASSERT(mSRIDataVerifier); @@ -766,6 +771,17 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest, nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream, mPipeOutputStream, aCount, &aRead); + + // If no data was read, it's possible the output stream is closed but the + // ReadSegments call followed its contract of returning NS_OK despite write + // errors. Unfortunately, nsIOutputStream has an ill-conceived contract when + // taken together with ReadSegments' contract, because the pipe will just + // NS_OK if we try and invoke its Write* functions ourselves with a 0 count. + // So we must just assume the pipe is broken. + if (aRead == 0 && aCount != 0) { + return NS_BASE_STREAM_CLOSED; + } + return rv; } diff --git a/dom/smil/nsSMILCSSProperty.cpp b/dom/smil/nsSMILCSSProperty.cpp index def89ef9f6..bbe91b5408 100644 --- a/dom/smil/nsSMILCSSProperty.cpp +++ b/dom/smil/nsSMILCSSProperty.cpp @@ -194,6 +194,7 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID) // writing-mode switch (aPropID) { + case eCSSProperty_caret_color: case eCSSProperty_clip: case eCSSProperty_clip_rule: case eCSSProperty_clip_path: diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 72923c4b7f..a9e6354abe 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -1831,8 +1831,7 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder, nscolor nsIFrame::GetCaretColorAt(int32_t aOffset) { - // Use text color. - return StyleColor()->mColor; + return nsLayoutUtils::GetColor(this, eCSSProperty_caret_color); } bool diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index fcce7f3f65..4decdc8ec9 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3947,11 +3947,18 @@ nsTextPaintStyle::InitSelectionColorsAndShadow() if (selectionElement && selectionStatus == nsISelectionController::SELECTION_ON) { RefPtr sc = nullptr; + // Probe for both selection and -moz-selection sc = mPresContext->StyleSet()-> ProbePseudoElementStyle(selectionElement, - CSSPseudoElementType::mozSelection, + CSSPseudoElementType::selection, mFrame->StyleContext()); - // Use -moz-selection pseudo class. + if (!sc) { + sc = mPresContext->StyleSet()-> + ProbePseudoElementStyle(selectionElement, + CSSPseudoElementType::mozSelection, + mFrame->StyleContext()); + } + // Use selection pseudo class. if (sc) { mSelectionBGColor = sc->GetVisitedDependentColor(eCSSProperty_background_color); diff --git a/layout/inspector/tests/test_getCSSPseudoElementNames.html b/layout/inspector/tests/test_getCSSPseudoElementNames.html index cdb4572d45..8879f21dc4 100644 --- a/layout/inspector/tests/test_getCSSPseudoElementNames.html +++ b/layout/inspector/tests/test_getCSSPseudoElementNames.html @@ -16,6 +16,7 @@ ":first-letter", ":first-line", ":placeholder", + ":selection", ":-moz-color-swatch", ":-moz-focus-inner", ":-moz-focus-outer", diff --git a/layout/reftests/image/reftest.list b/layout/reftests/image/reftest.list index 1a610811d8..0eddb61fc3 100644 --- a/layout/reftests/image/reftest.list +++ b/layout/reftests/image/reftest.list @@ -126,3 +126,5 @@ fuzzy(1,1) == image-orientation-background.html?90&flip image-orientation-r == image-resize-percent-height.html image-resize-ref.html == image-resize-percent-width.html image-resize-ref.html + +== unknown-protocol.html unknown-protocol-ref.html diff --git a/layout/reftests/image/unknown-protocol-ref.html b/layout/reftests/image/unknown-protocol-ref.html new file mode 100644 index 0000000000..b5bb326eef --- /dev/null +++ b/layout/reftests/image/unknown-protocol-ref.html @@ -0,0 +1 @@ + diff --git a/layout/reftests/image/unknown-protocol.html b/layout/reftests/image/unknown-protocol.html new file mode 100644 index 0000000000..ef06881b7b --- /dev/null +++ b/layout/reftests/image/unknown-protocol.html @@ -0,0 +1 @@ + diff --git a/layout/style/StyleAnimationValue.cpp b/layout/style/StyleAnimationValue.cpp index ca0b1133f4..ff67835536 100644 --- a/layout/style/StyleAnimationValue.cpp +++ b/layout/style/StyleAnimationValue.cpp @@ -4468,8 +4468,12 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty, StyleDataAtOffset(styleStruct, ssOffset)); return true; case eStyleAnimType_ComplexColor: { - aComputedValue.SetComplexColorValue( - StyleDataAtOffset(styleStruct, ssOffset)); + auto& color = StyleDataAtOffset(styleStruct, ssOffset); + if (color.mIsAuto) { + aComputedValue.SetAutoValue(); + } else { + aComputedValue.SetComplexColorValue(color); + } return true; } case eStyleAnimType_PaintServer: { @@ -4782,7 +4786,9 @@ StyleAnimationValue::SetCurrentColorValue() void StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor) { - if (aColor.IsCurrentColor()) { + if (aColor.mIsAuto) { + SetAutoValue(); + } else if (aColor.IsCurrentColor()) { SetCurrentColorValue(); } else if (aColor.IsNumericColor()) { SetColorValue(aColor.mColor); diff --git a/layout/style/StyleComplexColor.h b/layout/style/StyleComplexColor.h index c6dd57a727..f3ff126a40 100644 --- a/layout/style/StyleComplexColor.h +++ b/layout/style/StyleComplexColor.h @@ -23,16 +23,29 @@ struct StyleComplexColor { nscolor mColor; uint8_t mForegroundRatio; + // Whether the complex color represents a computed-value time auto + // value. This is only a flag indicating that this value should not + // be interpolatable with other colors, while other fields still + // represents the actual used color of this value. + bool mIsAuto; - static StyleComplexColor FromColor(nscolor aColor) { return {aColor, 0}; } - static StyleComplexColor CurrentColor() { return {NS_RGBA(0, 0, 0, 0), 255}; } + static StyleComplexColor FromColor(nscolor aColor) { + return {aColor, 0, false}; + } + static StyleComplexColor CurrentColor() { + return {NS_RGBA(0, 0, 0, 0), 255, false}; + } + static StyleComplexColor Auto() { + return {NS_RGBA(0, 0, 0, 0), 255, true}; + } bool IsNumericColor() const { return mForegroundRatio == 0; } bool IsCurrentColor() const { return mForegroundRatio == 255; } bool operator==(const StyleComplexColor& aOther) const { return mForegroundRatio == aOther.mForegroundRatio && - (IsCurrentColor() || mColor == aOther.mColor); + (IsCurrentColor() || mColor == aOther.mColor) && + mIsAuto == aOther.mIsAuto; } bool operator!=(const StyleComplexColor& aOther) const { return !(*this == aOther); diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index 8900192454..4f79db5a55 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1394,6 +1394,17 @@ CSS_PROP_TABLEBORDER( kCaptionSideKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_Discrete) +CSS_PROP_USERINTERFACE( + caret-color, + caret_color, + CaretColor, + CSS_PROPERTY_PARSE_VALUE | + CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED, + "", + VARIANT_AUTO | VARIANT_HC, + nullptr, + offsetof(nsStyleUserInterface, mCaretColor), + eStyleAnimType_ComplexColor) CSS_PROP_DISPLAY( clear, clear, diff --git a/layout/style/nsCSSPseudoElementList.h b/layout/style/nsCSSPseudoElementList.h index 552c76734a..b8393d3952 100644 --- a/layout/style/nsCSSPseudoElementList.h +++ b/layout/style/nsCSSPseudoElementList.h @@ -37,6 +37,9 @@ CSS_PSEUDO_ELEMENT(firstLine, ":first-line", CSS_PSEUDO_ELEMENT_IS_CSS2 | CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS) +CSS_PSEUDO_ELEMENT(selection, ":selection", + CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS) +// Keep the prefixed version for now. CSS_PSEUDO_ELEMENT(mozSelection, ":-moz-selection", CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS) diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 610039fbaf..080932af23 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -4187,6 +4187,14 @@ nsComputedDOMStyle::DoGetUnicodeBidi() return val.forget(); } +already_AddRefed +nsComputedDOMStyle::DoGetCaretColor() +{ + RefPtr val = new nsROCSSPrimitiveValue; + SetValueFromComplexColor(val, StyleUserInterface()->mCaretColor); + return val.forget(); +} + already_AddRefed nsComputedDOMStyle::DoGetCursor() { diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 5af518c2eb..35a6142688 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -488,6 +488,7 @@ private: already_AddRefed DoGetShapeOutside(); /* User interface properties */ + already_AddRefed DoGetCaretColor(); already_AddRefed DoGetCursor(); already_AddRefed DoGetForceBrokenImageIcon(); already_AddRefed DoGetIMEMode(); diff --git a/layout/style/nsComputedDOMStylePropertyList.h b/layout/style/nsComputedDOMStylePropertyList.h index 5572818105..8d4d8e45e2 100644 --- a/layout/style/nsComputedDOMStylePropertyList.h +++ b/layout/style/nsComputedDOMStylePropertyList.h @@ -101,6 +101,7 @@ COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak) COMPUTED_STYLE_PROP(box_shadow, BoxShadow) COMPUTED_STYLE_PROP(box_sizing, BoxSizing) COMPUTED_STYLE_PROP(caption_side, CaptionSide) +COMPUTED_STYLE_PROP(caret_color, CaretColor) COMPUTED_STYLE_PROP(clear, Clear) COMPUTED_STYLE_PROP(clip, Clip) COMPUTED_STYLE_PROP(color, Color) diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index fb592abdd0..c32369e9bb 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -1151,13 +1151,16 @@ SetComplexColor(const nsCSSValue& aValue, aResult = StyleComplexColor::CurrentColor(); } else if (unit == eCSSUnit_ComplexColor) { aResult = aValue.GetStyleComplexColorValue(); + } else if (unit == eCSSUnit_Auto) { + aResult = StyleComplexColor::Auto(); } else { + nscolor resultColor; if (!SetColor(aValue, aParentColor.mColor, aPresContext, - nullptr, aResult.mColor, aConditions)) { + nullptr, resultColor, aConditions)) { MOZ_ASSERT_UNREACHABLE("Unknown color value"); return; } - aResult.mForegroundRatio = 0; + aResult = StyleComplexColor::FromColor(resultColor); } } @@ -5138,6 +5141,13 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct, { COMPUTE_START_INHERITED(UserInterface, ui, parentUI) + auto setComplexColor = [&](const nsCSSValue* aValue, + StyleComplexColor nsStyleUserInterface::* aField) { + SetComplexColor(*aValue, parentUI->*aField, + StyleComplexColor::Auto(), + mPresContext, ui->*aField, conditions); + }; + // cursor: enum, url, inherit const nsCSSValue* cursorValue = aRuleData->ValueForCursor(); nsCSSUnit cursorUnit = cursorValue->GetUnit(); @@ -5209,6 +5219,10 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct, parentUI->mPointerEvents, NS_STYLE_POINTER_EVENTS_AUTO); + // caret-color: auto, color, inherit + setComplexColor(aRuleData->ValueForCaretColor(), + &nsStyleUserInterface::mCaretColor); + COMPUTE_END_INHERITED(UserInterface, ui) } diff --git a/layout/style/nsStyleContext.cpp b/layout/style/nsStyleContext.cpp index 4b1a14897a..38b422bd73 100644 --- a/layout/style/nsStyleContext.cpp +++ b/layout/style/nsStyleContext.cpp @@ -1255,6 +1255,17 @@ nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext, } } + // NB: Calling Peek on |this|, not |thisVis| (see above). + if (!change && PeekStyleUserInterface()) { + const nsStyleUserInterface *thisVisUserInterface = thisVis->StyleUserInterface(); + const nsStyleUserInterface *otherVisUserInterface = otherVis->StyleUserInterface(); + if (thisVisUserInterface->mCaretColor != + otherVisUserInterface->mCaretColor) { + change = true; + } + } + + if (change) { hint |= nsChangeHint_RepaintFrame; } @@ -1487,6 +1498,9 @@ ExtractColor(nsCSSPropertyID aProperty, case StyleAnimationValue::eUnit_ComplexColor: return Some(aStyleContext->StyleColor()-> CalcComplexColor(val.GetStyleComplexColorValue())); + case StyleAnimationValue::eUnit_Auto: + return Some(aStyleContext->StyleColor()-> + CalcComplexColor(StyleComplexColor::Auto())); default: return Nothing(); } @@ -1508,7 +1522,8 @@ static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } }; nscolor nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty) { - NS_ASSERTION(aProperty == eCSSProperty_color || + NS_ASSERTION(aProperty == eCSSProperty_caret_color || + aProperty == eCSSProperty_color || aProperty == eCSSProperty_background_color || aProperty == eCSSProperty_border_top_color || aProperty == eCSSProperty_border_right_color || diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index cb70f03a3d..c0ea9c256c 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -4023,6 +4023,7 @@ nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext) , mUserFocus(StyleUserFocus::None) , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO) , mCursor(NS_STYLE_CURSOR_AUTO) + , mCaretColor(StyleComplexColor::Auto()) { MOZ_COUNT_CTOR(nsStyleUserInterface); } @@ -4034,6 +4035,7 @@ nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) , mPointerEvents(aSource.mPointerEvents) , mCursor(aSource.mCursor) , mCursorImages(aSource.mCursorImages) + , mCaretColor(aSource.mCaretColor) { MOZ_COUNT_CTOR(nsStyleUserInterface); } @@ -4082,6 +4084,10 @@ nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const hint |= nsChangeHint_NeutralChange; } + if (mCaretColor != aNewData.mCaretColor) { + hint |= nsChangeHint_RepaintFrame; + } + return hint; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index e4d02a24a7..88000c722a 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -3416,6 +3416,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface uint8_t mCursor; // [inherited] See nsStyleConsts.h nsTArray mCursorImages; // [inherited] images and coords + mozilla::StyleComplexColor mCaretColor; // [inherited] inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const; }; diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 1d830b188d..d647b57161 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -2836,6 +2836,18 @@ var gCSSProperties = { other_values: [ "bottom", "left", "right", "top-outside", "bottom-outside" ], invalid_values: [] }, + "caret-color": { + domProp: "caretColor", + inherited: true, + type: CSS_TYPE_LONGHAND, + prerequisites: { "color": "black" }, + // Though "auto" is an independent computed-value time keyword value, + // it is not distinguishable from currentcolor because getComputedStyle + // always returns used value for . + initial_values: [ "auto", "currentcolor", "black", "rgb(0,0,0)" ], + other_values: [ "green", "transparent", "rgba(128,128,128,.5)", "#123" ], + invalid_values: [ "#0", "#00", "#00000", "cc00ff" ] + }, "clear": { domProp: "clear", inherited: false, diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html index 29e2ae24c2..f188f4f6fb 100644 --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -1373,6 +1373,21 @@ function test_true_currentcolor_transition(prop, get_color=(x => x), is_shorthan div.style.removeProperty("color"); } +function test_auto_color_transition(prop, get_color=(x => x), is_shorthand=false) { + const msg_prefix = `color-valued property ${prop}: `; + const test_color = "rgb(51, 102, 153)"; + div.style.setProperty("transition-property", "none", ""); + div.style.setProperty(prop, "auto", ""); + let used_value_of_auto = get_color(cs.getPropertyValue(prop)); + isnot(used_value_of_auto, test_color, + msg_prefix + "ensure used auto value is different than our test color"); + + div.style.setProperty("transition-property", prop, ""); + div.style.setProperty(prop, test_color, ""); + is(get_color(cs.getPropertyValue(prop)), test_color, + msg_prefix + "not interpolatable between auto and rgb color"); +} + function get_color_from_shorthand_value(value) { var m = value.match(/rgba?\([^, ]*, [^, ]*, [^, ]*(?:, [^, ]*)?\)/); isnot(m, null, "shorthand property value should contain color");