Implement CSS caret-color.
parent
75fc2843ab
commit
4fe446773f
|
@ -2872,6 +2872,7 @@ exports.CSS_PROPERTIES = {
|
||||||
"box-shadow",
|
"box-shadow",
|
||||||
"box-sizing",
|
"box-sizing",
|
||||||
"caption-side",
|
"caption-side",
|
||||||
|
"caret-color",
|
||||||
"clear",
|
"clear",
|
||||||
"clip",
|
"clip",
|
||||||
"clip-path",
|
"clip-path",
|
||||||
|
@ -5277,6 +5278,28 @@ exports.CSS_PROPERTIES = {
|
||||||
"unset"
|
"unset"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"caret-color": {
|
||||||
|
"isInherited": true,
|
||||||
|
"subproperties": [
|
||||||
|
"caret-color"
|
||||||
|
],
|
||||||
|
"supports": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"values": [
|
||||||
|
"COLOR",
|
||||||
|
"auto",
|
||||||
|
"currentColor",
|
||||||
|
"hsl",
|
||||||
|
"hsla",
|
||||||
|
"inherit",
|
||||||
|
"initial",
|
||||||
|
"rgb",
|
||||||
|
"rgba",
|
||||||
|
"transparent",
|
||||||
|
"unset"
|
||||||
|
]
|
||||||
|
},
|
||||||
"clear": {
|
"clear": {
|
||||||
"isInherited": false,
|
"isInherited": false,
|
||||||
"subproperties": [
|
"subproperties": [
|
||||||
|
|
|
@ -194,6 +194,7 @@ nsSMILCSSProperty::IsPropertyAnimatable(nsCSSPropertyID aPropID)
|
||||||
// writing-mode
|
// writing-mode
|
||||||
|
|
||||||
switch (aPropID) {
|
switch (aPropID) {
|
||||||
|
case eCSSProperty_caret_color:
|
||||||
case eCSSProperty_clip:
|
case eCSSProperty_clip:
|
||||||
case eCSSProperty_clip_rule:
|
case eCSSProperty_clip_rule:
|
||||||
case eCSSProperty_clip_path:
|
case eCSSProperty_clip_path:
|
||||||
|
|
|
@ -1831,8 +1831,7 @@ nsIFrame::DisplayCaret(nsDisplayListBuilder* aBuilder,
|
||||||
nscolor
|
nscolor
|
||||||
nsIFrame::GetCaretColorAt(int32_t aOffset)
|
nsIFrame::GetCaretColorAt(int32_t aOffset)
|
||||||
{
|
{
|
||||||
// Use text color.
|
return nsLayoutUtils::GetColor(this, eCSSProperty_caret_color);
|
||||||
return StyleColor()->mColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -4468,8 +4468,12 @@ StyleAnimationValue::ExtractComputedValue(nsCSSPropertyID aProperty,
|
||||||
StyleDataAtOffset<nscolor>(styleStruct, ssOffset));
|
StyleDataAtOffset<nscolor>(styleStruct, ssOffset));
|
||||||
return true;
|
return true;
|
||||||
case eStyleAnimType_ComplexColor: {
|
case eStyleAnimType_ComplexColor: {
|
||||||
aComputedValue.SetComplexColorValue(
|
auto& color = StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset);
|
||||||
StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset));
|
if (color.mIsAuto) {
|
||||||
|
aComputedValue.SetAutoValue();
|
||||||
|
} else {
|
||||||
|
aComputedValue.SetComplexColorValue(color);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case eStyleAnimType_PaintServer: {
|
case eStyleAnimType_PaintServer: {
|
||||||
|
@ -4782,7 +4786,9 @@ StyleAnimationValue::SetCurrentColorValue()
|
||||||
void
|
void
|
||||||
StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
|
StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
|
||||||
{
|
{
|
||||||
if (aColor.IsCurrentColor()) {
|
if (aColor.mIsAuto) {
|
||||||
|
SetAutoValue();
|
||||||
|
} else if (aColor.IsCurrentColor()) {
|
||||||
SetCurrentColorValue();
|
SetCurrentColorValue();
|
||||||
} else if (aColor.IsNumericColor()) {
|
} else if (aColor.IsNumericColor()) {
|
||||||
SetColorValue(aColor.mColor);
|
SetColorValue(aColor.mColor);
|
||||||
|
|
|
@ -23,16 +23,29 @@ struct StyleComplexColor
|
||||||
{
|
{
|
||||||
nscolor mColor;
|
nscolor mColor;
|
||||||
uint8_t mForegroundRatio;
|
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 FromColor(nscolor aColor) {
|
||||||
static StyleComplexColor CurrentColor() { return {NS_RGBA(0, 0, 0, 0), 255}; }
|
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 IsNumericColor() const { return mForegroundRatio == 0; }
|
||||||
bool IsCurrentColor() const { return mForegroundRatio == 255; }
|
bool IsCurrentColor() const { return mForegroundRatio == 255; }
|
||||||
|
|
||||||
bool operator==(const StyleComplexColor& aOther) const {
|
bool operator==(const StyleComplexColor& aOther) const {
|
||||||
return mForegroundRatio == aOther.mForegroundRatio &&
|
return mForegroundRatio == aOther.mForegroundRatio &&
|
||||||
(IsCurrentColor() || mColor == aOther.mColor);
|
(IsCurrentColor() || mColor == aOther.mColor) &&
|
||||||
|
mIsAuto == aOther.mIsAuto;
|
||||||
}
|
}
|
||||||
bool operator!=(const StyleComplexColor& aOther) const {
|
bool operator!=(const StyleComplexColor& aOther) const {
|
||||||
return !(*this == aOther);
|
return !(*this == aOther);
|
||||||
|
|
|
@ -1394,6 +1394,17 @@ CSS_PROP_TABLEBORDER(
|
||||||
kCaptionSideKTable,
|
kCaptionSideKTable,
|
||||||
CSS_PROP_NO_OFFSET,
|
CSS_PROP_NO_OFFSET,
|
||||||
eStyleAnimType_Discrete)
|
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(
|
CSS_PROP_DISPLAY(
|
||||||
clear,
|
clear,
|
||||||
clear,
|
clear,
|
||||||
|
|
|
@ -4187,6 +4187,14 @@ nsComputedDOMStyle::DoGetUnicodeBidi()
|
||||||
return val.forget();
|
return val.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
already_AddRefed<CSSValue>
|
||||||
|
nsComputedDOMStyle::DoGetCaretColor()
|
||||||
|
{
|
||||||
|
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
|
||||||
|
SetValueFromComplexColor(val, StyleUserInterface()->mCaretColor);
|
||||||
|
return val.forget();
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<CSSValue>
|
already_AddRefed<CSSValue>
|
||||||
nsComputedDOMStyle::DoGetCursor()
|
nsComputedDOMStyle::DoGetCursor()
|
||||||
{
|
{
|
||||||
|
|
|
@ -488,6 +488,7 @@ private:
|
||||||
already_AddRefed<CSSValue> DoGetShapeOutside();
|
already_AddRefed<CSSValue> DoGetShapeOutside();
|
||||||
|
|
||||||
/* User interface properties */
|
/* User interface properties */
|
||||||
|
already_AddRefed<CSSValue> DoGetCaretColor();
|
||||||
already_AddRefed<CSSValue> DoGetCursor();
|
already_AddRefed<CSSValue> DoGetCursor();
|
||||||
already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
|
already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
|
||||||
already_AddRefed<CSSValue> DoGetIMEMode();
|
already_AddRefed<CSSValue> DoGetIMEMode();
|
||||||
|
|
|
@ -101,6 +101,7 @@ COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak)
|
||||||
COMPUTED_STYLE_PROP(box_shadow, BoxShadow)
|
COMPUTED_STYLE_PROP(box_shadow, BoxShadow)
|
||||||
COMPUTED_STYLE_PROP(box_sizing, BoxSizing)
|
COMPUTED_STYLE_PROP(box_sizing, BoxSizing)
|
||||||
COMPUTED_STYLE_PROP(caption_side, CaptionSide)
|
COMPUTED_STYLE_PROP(caption_side, CaptionSide)
|
||||||
|
COMPUTED_STYLE_PROP(caret_color, CaretColor)
|
||||||
COMPUTED_STYLE_PROP(clear, Clear)
|
COMPUTED_STYLE_PROP(clear, Clear)
|
||||||
COMPUTED_STYLE_PROP(clip, Clip)
|
COMPUTED_STYLE_PROP(clip, Clip)
|
||||||
COMPUTED_STYLE_PROP(color, Color)
|
COMPUTED_STYLE_PROP(color, Color)
|
||||||
|
|
|
@ -1151,13 +1151,16 @@ SetComplexColor(const nsCSSValue& aValue,
|
||||||
aResult = StyleComplexColor::CurrentColor();
|
aResult = StyleComplexColor::CurrentColor();
|
||||||
} else if (unit == eCSSUnit_ComplexColor) {
|
} else if (unit == eCSSUnit_ComplexColor) {
|
||||||
aResult = aValue.GetStyleComplexColorValue();
|
aResult = aValue.GetStyleComplexColorValue();
|
||||||
|
} else if (unit == eCSSUnit_Auto) {
|
||||||
|
aResult = StyleComplexColor::Auto();
|
||||||
} else {
|
} else {
|
||||||
|
nscolor resultColor;
|
||||||
if (!SetColor(aValue, aParentColor.mColor, aPresContext,
|
if (!SetColor(aValue, aParentColor.mColor, aPresContext,
|
||||||
nullptr, aResult.mColor, aConditions)) {
|
nullptr, resultColor, aConditions)) {
|
||||||
MOZ_ASSERT_UNREACHABLE("Unknown color value");
|
MOZ_ASSERT_UNREACHABLE("Unknown color value");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
aResult.mForegroundRatio = 0;
|
aResult = StyleComplexColor::FromColor(resultColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5138,6 +5141,13 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
|
||||||
{
|
{
|
||||||
COMPUTE_START_INHERITED(UserInterface, ui, parentUI)
|
COMPUTE_START_INHERITED(UserInterface, ui, parentUI)
|
||||||
|
|
||||||
|
auto setComplexColor = [&](const nsCSSValue* aValue,
|
||||||
|
StyleComplexColor nsStyleUserInterface::* aField) {
|
||||||
|
SetComplexColor<eUnsetInherit>(*aValue, parentUI->*aField,
|
||||||
|
StyleComplexColor::Auto(),
|
||||||
|
mPresContext, ui->*aField, conditions);
|
||||||
|
};
|
||||||
|
|
||||||
// cursor: enum, url, inherit
|
// cursor: enum, url, inherit
|
||||||
const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
|
const nsCSSValue* cursorValue = aRuleData->ValueForCursor();
|
||||||
nsCSSUnit cursorUnit = cursorValue->GetUnit();
|
nsCSSUnit cursorUnit = cursorValue->GetUnit();
|
||||||
|
@ -5209,6 +5219,10 @@ nsRuleNode::ComputeUserInterfaceData(void* aStartStruct,
|
||||||
parentUI->mPointerEvents,
|
parentUI->mPointerEvents,
|
||||||
NS_STYLE_POINTER_EVENTS_AUTO);
|
NS_STYLE_POINTER_EVENTS_AUTO);
|
||||||
|
|
||||||
|
// caret-color: auto, color, inherit
|
||||||
|
setComplexColor(aRuleData->ValueForCaretColor(),
|
||||||
|
&nsStyleUserInterface::mCaretColor);
|
||||||
|
|
||||||
COMPUTE_END_INHERITED(UserInterface, ui)
|
COMPUTE_END_INHERITED(UserInterface, ui)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
if (change) {
|
||||||
hint |= nsChangeHint_RepaintFrame;
|
hint |= nsChangeHint_RepaintFrame;
|
||||||
}
|
}
|
||||||
|
@ -1487,6 +1498,9 @@ ExtractColor(nsCSSPropertyID aProperty,
|
||||||
case StyleAnimationValue::eUnit_ComplexColor:
|
case StyleAnimationValue::eUnit_ComplexColor:
|
||||||
return Some(aStyleContext->StyleColor()->
|
return Some(aStyleContext->StyleColor()->
|
||||||
CalcComplexColor(val.GetStyleComplexColorValue()));
|
CalcComplexColor(val.GetStyleComplexColorValue()));
|
||||||
|
case StyleAnimationValue::eUnit_Auto:
|
||||||
|
return Some(aStyleContext->StyleColor()->
|
||||||
|
CalcComplexColor(StyleComplexColor::Auto()));
|
||||||
default:
|
default:
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
|
@ -1508,7 +1522,8 @@ static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
|
||||||
nscolor
|
nscolor
|
||||||
nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty)
|
nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty)
|
||||||
{
|
{
|
||||||
NS_ASSERTION(aProperty == eCSSProperty_color ||
|
NS_ASSERTION(aProperty == eCSSProperty_caret_color ||
|
||||||
|
aProperty == eCSSProperty_color ||
|
||||||
aProperty == eCSSProperty_background_color ||
|
aProperty == eCSSProperty_background_color ||
|
||||||
aProperty == eCSSProperty_border_top_color ||
|
aProperty == eCSSProperty_border_top_color ||
|
||||||
aProperty == eCSSProperty_border_right_color ||
|
aProperty == eCSSProperty_border_right_color ||
|
||||||
|
|
|
@ -4023,6 +4023,7 @@ nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
|
||||||
, mUserFocus(StyleUserFocus::None)
|
, mUserFocus(StyleUserFocus::None)
|
||||||
, mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
|
, mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
|
||||||
, mCursor(NS_STYLE_CURSOR_AUTO)
|
, mCursor(NS_STYLE_CURSOR_AUTO)
|
||||||
|
, mCaretColor(StyleComplexColor::Auto())
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
||||||
}
|
}
|
||||||
|
@ -4034,6 +4035,7 @@ nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
|
||||||
, mPointerEvents(aSource.mPointerEvents)
|
, mPointerEvents(aSource.mPointerEvents)
|
||||||
, mCursor(aSource.mCursor)
|
, mCursor(aSource.mCursor)
|
||||||
, mCursorImages(aSource.mCursorImages)
|
, mCursorImages(aSource.mCursorImages)
|
||||||
|
, mCaretColor(aSource.mCaretColor)
|
||||||
{
|
{
|
||||||
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
MOZ_COUNT_CTOR(nsStyleUserInterface);
|
||||||
}
|
}
|
||||||
|
@ -4082,6 +4084,10 @@ nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
|
||||||
hint |= nsChangeHint_NeutralChange;
|
hint |= nsChangeHint_NeutralChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCaretColor != aNewData.mCaretColor) {
|
||||||
|
hint |= nsChangeHint_RepaintFrame;
|
||||||
|
}
|
||||||
|
|
||||||
return hint;
|
return hint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3416,6 +3416,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface
|
||||||
|
|
||||||
uint8_t mCursor; // [inherited] See nsStyleConsts.h
|
uint8_t mCursor; // [inherited] See nsStyleConsts.h
|
||||||
nsTArray<nsCursorImage> mCursorImages; // [inherited] images and coords
|
nsTArray<nsCursorImage> mCursorImages; // [inherited] images and coords
|
||||||
|
mozilla::StyleComplexColor mCaretColor; // [inherited]
|
||||||
|
|
||||||
inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
|
inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2836,6 +2836,18 @@ var gCSSProperties = {
|
||||||
other_values: [ "bottom", "left", "right", "top-outside", "bottom-outside" ],
|
other_values: [ "bottom", "left", "right", "top-outside", "bottom-outside" ],
|
||||||
invalid_values: []
|
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 <color>.
|
||||||
|
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": {
|
"clear": {
|
||||||
domProp: "clear",
|
domProp: "clear",
|
||||||
inherited: false,
|
inherited: false,
|
||||||
|
|
|
@ -1373,6 +1373,21 @@ function test_true_currentcolor_transition(prop, get_color=(x => x), is_shorthan
|
||||||
div.style.removeProperty("color");
|
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) {
|
function get_color_from_shorthand_value(value) {
|
||||||
var m = value.match(/rgba?\([^, ]*, [^, ]*, [^, ]*(?:, [^, ]*)?\)/);
|
var m = value.match(/rgba?\([^, ]*, [^, ]*, [^, ]*(?:, [^, ]*)?\)/);
|
||||||
isnot(m, null, "shorthand property value should contain color");
|
isnot(m, null, "shorthand property value should contain color");
|
||||||
|
|
Loading…
Reference in New Issue