@@ -104,7 +104,8 @@ const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen";
104104#[ derive( Clone , JSTraceable , MallocSizeOf ) ]
105105#[ cfg_attr( crown, crown:: unrooted_must_root_lint:: must_root) ]
106106/// Contains reference to text control inner editor and placeholder container element in the UA
107- /// shadow tree for `<input type=text>`. The following is the structure of the shadow tree.
107+ /// shadow tree for `text`, `password`, `url`, `tel`, and `email` input. The following is the
108+ /// structure of the shadow tree.
108109///
109110/// ```
110111/// <input type="text">
@@ -115,6 +116,7 @@ const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen";
115116/// </div>
116117/// </input>
117118/// ```
119+ ///
118120// TODO(stevennovaryo): We are trying to use CSS to mimic Chrome and Firefox's layout for the <input> element.
119121// But, this could be slower in performance and does have some discrepancies. For example,
120122// they would try to vertically align <input> text baseline with the baseline of other
@@ -128,7 +130,7 @@ struct InputTypeTextShadowTree {
128130
129131#[ derive( Clone , JSTraceable , MallocSizeOf ) ]
130132#[ cfg_attr( crown, crown:: unrooted_must_root_lint:: must_root) ]
131- /// Contains references to the elements in the shadow tree for `<input type=range >`.
133+ /// Contains references to the elements in the shadow tree for `<input type=color >`.
132134///
133135/// The shadow tree consists of a single div with the currently selected color as
134136/// the background.
@@ -219,10 +221,11 @@ pub(crate) enum InputType {
219221}
220222
221223impl InputType {
222- // Note that Password is not included here since it is handled
223- // slightly differently, with placeholder characters shown rather
224- // than the underlying value.
225- fn is_textual ( & self ) -> bool {
224+ /// Defines which input type that should perform like a text input,
225+ /// specifically when it is interacting with JS. Note that Password
226+ /// is not included here since it is handled slightly differently,
227+ /// with placeholder characters shown rather than the underlying value.
228+ pub ( crate ) fn is_textual ( & self ) -> bool {
226229 matches ! (
227230 * self ,
228231 InputType :: Date |
@@ -1238,9 +1241,35 @@ impl HTMLInputElement {
12381241 . expect ( "UA shadow tree was not created" )
12391242 }
12401243
1241- fn update_text_shadow_tree_if_needed ( & self , can_gc : CanGc ) {
1242- // Should only do this for `type=text` input.
1243- debug_assert_eq ! ( self . input_type( ) , InputType :: Text ) ;
1244+ /// Should this input type render as a basic text UA widget.
1245+ // TODO(#38251): Ideally, the most basic shadow dom should cover only `text`, `password`, `url`, `tel`,
1246+ // and `email`. But we are leaving the others textual inputs here while tackling them one
1247+ // by one.
1248+ pub ( crate ) fn is_textual_widget ( & self ) -> bool {
1249+ matches ! (
1250+ self . input_type( ) ,
1251+ InputType :: Date |
1252+ InputType :: DatetimeLocal |
1253+ InputType :: Email |
1254+ InputType :: Month |
1255+ InputType :: Number |
1256+ InputType :: Password |
1257+ InputType :: Range |
1258+ InputType :: Search |
1259+ InputType :: Tel |
1260+ InputType :: Text |
1261+ InputType :: Time |
1262+ InputType :: Url |
1263+ InputType :: Week
1264+ )
1265+ }
1266+
1267+ /// Construct the most basic shadow tree structure for textual input.
1268+ /// TODO(stevennovaryo): The rest of textual input shadow dom structure should act like an
1269+ /// exstension to this one.
1270+ fn update_textual_shadow_tree ( & self , can_gc : CanGc ) {
1271+ // Should only do this for textual input widget.
1272+ debug_assert ! ( self . is_textual_widget( ) ) ;
12441273
12451274 let text_shadow_tree = self . text_shadow_tree ( can_gc) ;
12461275 let value = self . Value ( ) ;
@@ -1253,9 +1282,15 @@ impl HTMLInputElement {
12531282 // This is also used to ensure that the caret will still be rendered when the input is empty.
12541283 // TODO: Could append `<br>` element to prevent collapses and avoid this hack, but we would
12551284 // need to fix the rendering of caret beforehand.
1256- let value_text = match value. is_empty ( ) {
1257- false => value,
1258- true => "\u{200B} " . into ( ) ,
1285+ let value_text = match ( value. is_empty ( ) , self . input_type ( ) ) {
1286+ // For a password input, we replace all of the character with its replacement char.
1287+ ( false , InputType :: Password ) => value
1288+ . chars ( )
1289+ . map ( |_| PASSWORD_REPLACEMENT_CHAR )
1290+ . collect :: < String > ( )
1291+ . into ( ) ,
1292+ ( false , _) => value,
1293+ ( true , _) => "\u{200B} " . into ( ) ,
12591294 } ;
12601295
12611296 // FIXME(stevennovaryo): Refactor this inside a TextControl wrapper
@@ -1269,7 +1304,7 @@ impl HTMLInputElement {
12691304 . SetData ( value_text) ;
12701305 }
12711306
1272- fn update_color_shadow_tree_if_needed ( & self , can_gc : CanGc ) {
1307+ fn update_color_shadow_tree ( & self , can_gc : CanGc ) {
12731308 // Should only do this for `type=color` input.
12741309 debug_assert_eq ! ( self . input_type( ) , InputType :: Color ) ;
12751310
@@ -1287,10 +1322,10 @@ impl HTMLInputElement {
12871322 . set_string_attribute ( & local_name ! ( "style" ) , style. into ( ) , can_gc) ;
12881323 }
12891324
1290- fn update_shadow_tree_if_needed ( & self , can_gc : CanGc ) {
1325+ fn update_shadow_tree ( & self , can_gc : CanGc ) {
12911326 match self . input_type ( ) {
1292- InputType :: Text => self . update_text_shadow_tree_if_needed ( can_gc) ,
1293- InputType :: Color => self . update_color_shadow_tree_if_needed ( can_gc) ,
1327+ _ if self . is_textual_widget ( ) => self . update_textual_shadow_tree ( can_gc) ,
1328+ InputType :: Color => self . update_color_shadow_tree ( can_gc) ,
12941329 _ => { } ,
12951330 }
12961331 }
@@ -1317,10 +1352,6 @@ impl<'dom> LayoutDom<'dom, HTMLInputElement> {
13171352 unsafe { self . unsafe_get ( ) . filelist . get_inner_as_layout ( ) }
13181353 }
13191354
1320- fn placeholder ( self ) -> & ' dom str {
1321- unsafe { self . unsafe_get ( ) . placeholder . borrow_for_layout ( ) }
1322- }
1323-
13241355 fn input_type ( self ) -> InputType {
13251356 self . unsafe_get ( ) . input_type . get ( )
13261357 }
@@ -1336,6 +1367,9 @@ impl<'dom> LayoutDom<'dom, HTMLInputElement> {
13361367}
13371368
13381369impl < ' dom > LayoutHTMLInputElementHelpers < ' dom > for LayoutDom < ' dom , HTMLInputElement > {
1370+ /// In the past, we are handling the display of <input> element inside the dom tree traversal.
1371+ /// With the introduction of shadow DOM, these implementations will be replaced one by one
1372+ /// and these will be obselete,
13391373 fn value_for_layout ( self ) -> Cow < ' dom , str > {
13401374 fn get_raw_attr_value < ' dom > (
13411375 input : LayoutDom < ' dom , HTMLInputElement > ,
@@ -1349,7 +1383,9 @@ impl<'dom> LayoutHTMLInputElementHelpers<'dom> for LayoutDom<'dom, HTMLInputElem
13491383 }
13501384
13511385 match self . input_type ( ) {
1352- InputType :: Checkbox | InputType :: Radio | InputType :: Image => "" . into ( ) ,
1386+ InputType :: Checkbox | InputType :: Radio | InputType :: Image | InputType :: Hidden => {
1387+ "" . into ( )
1388+ } ,
13531389 InputType :: File => {
13541390 let filelist = self . get_filelist ( ) ;
13551391 match filelist {
@@ -1372,31 +1408,23 @@ impl<'dom> LayoutHTMLInputElementHelpers<'dom> for LayoutDom<'dom, HTMLInputElem
13721408 InputType :: Button => get_raw_attr_value ( self , "" ) ,
13731409 InputType :: Submit => get_raw_attr_value ( self , DEFAULT_SUBMIT_VALUE ) ,
13741410 InputType :: Reset => get_raw_attr_value ( self , DEFAULT_RESET_VALUE ) ,
1375- InputType :: Password => {
1376- let text = self . get_raw_textinput_value ( ) ;
1377- if !text. is_empty ( ) {
1378- text. chars ( )
1379- . map ( |_| PASSWORD_REPLACEMENT_CHAR )
1380- . collect :: < String > ( )
1381- . into ( )
1382- } else {
1383- self . placeholder ( ) . into ( )
1384- }
1385- } ,
1386- InputType :: Color => {
1387- unreachable ! ( "Input type color is explicitly not rendered as text" ) ;
1388- } ,
1411+ // FIXME(#22728): input `type=range` has yet to be implemented.
1412+ InputType :: Range => "" . into ( ) ,
13891413 _ => {
1390- let text = self . get_raw_textinput_value ( ) ;
1391- if !text. is_empty ( ) {
1392- text. into ( )
1393- } else {
1394- self . placeholder ( ) . into ( )
1395- }
1414+ unreachable ! ( "Input with shadow tree should use internal shadow tree for layout" ) ;
13961415 } ,
13971416 }
13981417 }
13991418
1419+ /// Textual input, specifically text entry and domain specific input has
1420+ /// a default preferred size.
1421+ ///
1422+ /// <https://html.spec.whatwg.org/multipage/#the-input-element-as-a-text-entry-widget>
1423+ /// <https://html.spec.whatwg.org/multipage/#the-input-element-as-domain-specific-widgets>
1424+ // FIXME(stevennovaryo): Implement the calculation of default preferred size
1425+ // for domain specific input widgets correctly.
1426+ // FIXME(#4378): Implement the calculation of average character width for
1427+ // textual input correctly.
14001428 fn size_for_layout ( self ) -> u32 {
14011429 self . unsafe_get ( ) . size . get ( )
14021430 }
@@ -2228,7 +2256,7 @@ impl HTMLInputElement {
22282256 // Update the placeholder text in the text shadow tree.
22292257 // To increase the performance, we would only do this when it is necessary.
22302258 fn update_text_shadow_tree_placeholder ( & self , can_gc : CanGc ) {
2231- if self . input_type ( ) != InputType :: Text {
2259+ if ! self . is_textual_widget ( ) {
22322260 return ;
22332261 }
22342262
@@ -2690,7 +2718,7 @@ impl HTMLInputElement {
26902718
26912719 fn value_changed ( & self , can_gc : CanGc ) {
26922720 self . update_related_validity_states ( can_gc) ;
2693- self . update_shadow_tree_if_needed ( can_gc) ;
2721+ self . update_shadow_tree ( can_gc) ;
26942722 }
26952723
26962724 /// <https://html.spec.whatwg.org/multipage/#show-the-picker,-if-applicable>
@@ -3034,7 +3062,7 @@ impl VirtualMethods for HTMLInputElement {
30343062 // WHATWG-specified activation behaviors are handled elsewhere;
30353063 // this is for all the other things a UI click might do
30363064
3037- //TODO: set the editing position for text inputs
3065+ //TODO(#10083) : set the editing position for text inputs
30383066
30393067 if self . input_type ( ) . is_textual_or_password ( ) &&
30403068 // Check if we display a placeholder. Layout doesn't know about this.
0 commit comments