Bug 1063162 part 2 - Implement caret-color property. r?dholbert draft
authorXidorn Quan <me@upsuper.org>
Thu, 22 Dec 2016 11:04:15 +1100
changeset 453832 83f322618ba47c366eb29afb1159f0505a172a50
parent 452830 dfd8876b734c4656f2990b448d153500105dfeb2
child 540531 ec7e1ce453351baa4b1020fb209f2944ad752590
push id39741
push usermozilla@upsuper.org
push dateSun, 25 Dec 2016 13:14:58 +0000
reviewersdholbert
bugs1063162
milestone53.0a1
Bug 1063162 part 2 - Implement caret-color property. r?dholbert MozReview-Commit-ID: DH7CX1d477R
devtools/shared/css/generated/properties-db.js
layout/generic/nsFrame.cpp
layout/reftests/css-ui/caret-color-01-ref.html
layout/reftests/css-ui/caret-color-01.html
layout/reftests/css-ui/reftest.list
layout/reftests/reftest.list
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsComputedDOMStylePropertyList.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
layout/style/test/test_transitions_per_property.html
layout/tools/reftest/reftest-preferences.js
--- a/devtools/shared/css/generated/properties-db.js
+++ b/devtools/shared/css/generated/properties-db.js
@@ -2852,16 +2852,17 @@ exports.CSS_PROPERTIES = {
       "-moz-box-direction",
       "-moz-box-flex",
       "-moz-box-ordinal-group",
       "-moz-box-orient",
       "-moz-box-pack",
       "box-shadow",
       "box-sizing",
       "caption-side",
+      "caret-color",
       "clear",
       "clip",
       "clip-path",
       "clip-rule",
       "color",
       "color-adjust",
       "color-interpolation",
       "color-interpolation-filters",
@@ -5256,16 +5257,38 @@ exports.CSS_PROPERTIES = {
       "initial",
       "left",
       "right",
       "top",
       "top-outside",
       "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": [
       "clear"
     ],
     "supports": [],
     "values": [
       "both",
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1876,18 +1876,17 @@ nsIFrame::DisplayCaret(nsDisplayListBuil
     return;
 
   aList->AppendNewToTop(new (aBuilder) nsDisplayCaret(aBuilder, this));
 }
 
 nscolor
 nsIFrame::GetCaretColorAt(int32_t aOffset)
 {
-  // Use text color.
-  return StyleColor()->mColor;
+  return StyleColor()->CalcComplexColor(StyleUserInterface()->mCaretColor);
 }
 
 bool
 nsFrame::DisplayBackgroundUnconditional(nsDisplayListBuilder* aBuilder,
                                         const nsDisplayListSet& aLists,
                                         bool aForceBackground)
 {
   // Here we don't try to detect background propagation. Frames that might
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui/caret-color-01-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+div {
+  font: 16px/1 Ahem;
+  width: 1em;
+  background: green;
+}
+</style>
+<div><span></span></div>
+<script>
+let $div = document.querySelector('div');
+let $span = document.querySelector('span');
+$div.style.height = $span.getBoundingClientRect().height + 'px';
+</script>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui/caret-color-01.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<style>
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+textarea {
+  caret-color: green;
+  font: 16px/1 Ahem;
+  outline: none;
+  border: 0 none;
+  resize: none;
+  padding: 0;
+  margin: 0;
+}
+</style>
+<textarea autofocus></textarea>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-ui/reftest.list
@@ -0,0 +1,1 @@
+pref(ui.caretWidth,16) needs-focus == caret-color-01.html caret-color-01-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -125,16 +125,19 @@ include text-overflow/reftest.list
 include css-selectors/reftest.list
 
 # css sizing
 include css-sizing/reftest.list
 
 # css transitions
 include css-transitions/reftest.list
 
+# css ui
+include css-ui/reftest.list
+
 # css :-moz-ui-invalid
 include css-ui-invalid/reftest.list
 
 # css :-moz-ui-valid
 include css-ui-valid/reftest.list
 
 # css values and units
 include css-valuesandunits/reftest.list
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -1376,16 +1376,27 @@ CSS_PROP_TABLEBORDER(
     caption_side,
     CaptionSide,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     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,
     Clear,
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kClearKTable,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -4133,16 +4133,24 @@ nsComputedDOMStyle::DoGetUnicodeBidi()
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetIdent(
     nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mUnicodeBidi,
                                    nsCSSProps::kUnicodeBidiKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
+nsComputedDOMStyle::DoGetCaretColor()
+{
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  SetValueFromComplexColor(val, StyleUserInterface()->mCaretColor);
+  return val.forget();
+}
+
+already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetCursor()
 {
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
 
   const nsStyleUserInterface *ui = StyleUserInterface();
 
   for (const nsCursorImage& item : ui->mCursorImages) {
     RefPtr<nsDOMCSSValueList> itemList = GetROCSSValueList(false);
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -482,16 +482,17 @@ private:
   already_AddRefed<CSSValue> DoGetScrollSnapTypeY();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsX();
   already_AddRefed<CSSValue> DoGetScrollSnapPointsY();
   already_AddRefed<CSSValue> DoGetScrollSnapDestination();
   already_AddRefed<CSSValue> DoGetScrollSnapCoordinate();
   already_AddRefed<CSSValue> DoGetShapeOutside();
 
   /* User interface properties */
+  already_AddRefed<CSSValue> DoGetCaretColor();
   already_AddRefed<CSSValue> DoGetCursor();
   already_AddRefed<CSSValue> DoGetForceBrokenImageIcon();
   already_AddRefed<CSSValue> DoGetIMEMode();
   already_AddRefed<CSSValue> DoGetUserFocus();
   already_AddRefed<CSSValue> DoGetUserInput();
   already_AddRefed<CSSValue> DoGetUserModify();
   already_AddRefed<CSSValue> DoGetUserSelect();
   already_AddRefed<CSSValue> DoGetWindowDragging();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -96,16 +96,17 @@ COMPUTED_STYLE_PROP(border_top_right_rad
 COMPUTED_STYLE_PROP(border_top_style,              BorderTopStyle)
 COMPUTED_STYLE_PROP(border_top_width,              BorderTopWidth)
 //// COMPUTED_STYLE_PROP(border_width,             BorderWidth)
 COMPUTED_STYLE_PROP(bottom,                        Bottom)
 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)
 COMPUTED_STYLE_PROP(color_adjust,                  ColorAdjust)
 COMPUTED_STYLE_PROP(column_count,                  ColumnCount)
 COMPUTED_STYLE_PROP(column_fill,                   ColumnFill)
 COMPUTED_STYLE_PROP(column_gap,                    ColumnGap)
 //// COMPUTED_STYLE_PROP(column_rule,              ColumnRule)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1131,16 +1131,18 @@ SetComplexColor(const nsCSSValue& aValue
              (UnsetTo == eUnsetInherit && unit == eCSSUnit_Unset)) {
     aConditions.SetUncacheable();
     aResult = aParentColor;
   } else if (unit == eCSSUnit_EnumColor &&
              aValue.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
     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, resultColor, aConditions)) {
       MOZ_ASSERT_UNREACHABLE("Unknown color value");
       return;
     }
     aResult = StyleComplexColor::FromColor(resultColor);
@@ -5283,16 +5285,24 @@ nsRuleNode::ComputeUserInterfaceData(voi
 
   // pointer-events: enum, inherit, initial
   SetValue(*aRuleData->ValueForPointerEvents(), ui->mPointerEvents,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentUI->mPointerEvents,
            NS_STYLE_POINTER_EVENTS_AUTO);
 
+  // caret-color: auto, color, inherit
+  const nsCSSValue* caretColorValue = aRuleData->ValueForCaretColor();
+  SetComplexColor<eUnsetInherit>(*caretColorValue,
+                                 parentUI->mCaretColor,
+                                 StyleComplexColor::Auto(),
+                                 mPresContext,
+                                 ui->mCaretColor, conditions);
+
   COMPUTE_END_INHERITED(UserInterface, ui)
 }
 
 const void*
 nsRuleNode::ComputeUIResetData(void* aStartStruct,
                                const nsRuleData* aRuleData,
                                nsStyleContext* aContext,
                                nsRuleNode* aHighestNode,
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3968,27 +3968,29 @@ nsCursorImage::operator==(const nsCursor
 }
 
 nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
   : mUserInput(StyleUserInput::Auto)
   , mUserModify(StyleUserModify::ReadOnly)
   , mUserFocus(StyleUserFocus::None)
   , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
   , mCursor(NS_STYLE_CURSOR_AUTO)
+  , mCaretColor(StyleComplexColor::Auto())
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
   : mUserInput(aSource.mUserInput)
   , mUserModify(aSource.mUserModify)
   , mUserFocus(aSource.mUserFocus)
   , mPointerEvents(aSource.mPointerEvents)
   , mCursor(aSource.mCursor)
   , mCursorImages(aSource.mCursorImages)
+  , mCaretColor(aSource.mCaretColor)
 {
   MOZ_COUNT_CTOR(nsStyleUserInterface);
 }
 
 nsStyleUserInterface::~nsStyleUserInterface()
 {
   MOZ_COUNT_DTOR(nsStyleUserInterface);
 }
@@ -4040,16 +4042,20 @@ nsStyleUserInterface::CalcDifference(con
       hint |= nsChangeHint_NeutralChange;
     }
   }
 
   if (mUserFocus != aNewData.mUserFocus) {
     hint |= nsChangeHint_NeutralChange;
   }
 
+  if (mCaretColor != aNewData.mCaretColor) {
+    hint |= nsChangeHint_RepaintFrame;
+  }
+
   return hint;
 }
 
 //-----------------------
 // nsStyleUIReset
 //
 
 nsStyleUIReset::nsStyleUIReset(StyleStructContext aContext)
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -3390,16 +3390,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   mozilla::StyleUserInput   mUserInput;       // [inherited]
   mozilla::StyleUserModify  mUserModify;      // [inherited] (modify-content)
   mozilla::StyleUserFocus   mUserFocus;       // [inherited] (auto-select)
   uint8_t                   mPointerEvents;   // [inherited] see nsStyleConsts.h
 
   uint8_t mCursor;                            // [inherited] See nsStyleConsts.h
   nsTArray<nsCursorImage> mCursorImages;      // [inherited] images and coords
+  mozilla::StyleComplexColor mCaretColor;     // [inherited]
 
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL
 {
   explicit nsStyleXUL(StyleStructContext aContext);
   nsStyleXUL(const nsStyleXUL& aSource);
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -2831,16 +2831,28 @@ var gCSSProperties = {
   "caption-side": {
     domProp: "captionSide",
     inherited: true,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "top" ],
     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 <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": {
     domProp: "clear",
     inherited: false,
     type: CSS_TYPE_LONGHAND,
     initial_values: [ "none" ],
     other_values: [ "left", "right", "both" ],
     invalid_values: []
   },
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -124,16 +124,19 @@ var supported_properties = {
                         test_length_pair_transition_clamped ],
     "border-top-color": [ test_color_transition,
                           test_true_currentcolor_transition ],
     "border-top-width": [ test_length_transition,
                            test_length_clamped ],
     "bottom": [ test_length_transition, test_percent_transition,
                 test_length_percent_calc_transition,
                 test_length_unclamped, test_percent_unclamped ],
+    "caret-color": [ test_color_transition,
+                     test_true_currentcolor_transition,
+                     test_auto_color_transition ],
     "clip": [ test_rect_transition ],
     "clip-path": [ test_clip_path_transition ],
     "color": [ test_color_transition,
                test_currentcolor_transition ],
     "fill": [ test_color_transition,
               test_currentcolor_transition ],
     "fill-opacity" : [ test_float_zeroToOne_transition,
                        // opacity is clamped in computed style
--- a/layout/tools/reftest/reftest-preferences.js
+++ b/layout/tools/reftest/reftest-preferences.js
@@ -2,16 +2,17 @@
 // content XBL bindings, so we set this pref to true. In reftests, we're
 // more interested in testing the behavior of XBL as it works in chrome,
 // so we want this pref to be false.
 user_pref("dom.use_xbl_scopes_for_remote_xul", false);
 user_pref("gfx.color_management.mode", 2);
 user_pref("gfx.color_management.force_srgb", true);
 user_pref("browser.dom.window.dump.enabled", true);
 user_pref("ui.caretBlinkTime", -1);
+user_pref("ui.caretWidth", 1);
 user_pref("dom.send_after_paint_to_content", true);
 // no slow script dialogs
 user_pref("dom.max_script_run_time", 0);
 user_pref("dom.max_chrome_script_run_time", 0);
 user_pref("hangmonitor.timeout", 0);
 // Ensure autoplay is enabled for all platforms.
 user_pref("media.autoplay.enabled", true);
 // Disable updates