diff options
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/block.rs | 4 | ||||
-rw-r--r-- | components/layout/construct.rs | 31 | ||||
-rw-r--r-- | components/layout/fragment.rs | 50 | ||||
-rw-r--r-- | components/layout/inline.rs | 4 | ||||
-rw-r--r-- | components/layout/table.rs | 5 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 42 |
6 files changed, 100 insertions, 36 deletions
diff --git a/components/layout/block.rs b/components/layout/block.rs index 23a2381e754..40d5a89244f 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -1516,7 +1516,7 @@ impl Flow for BlockFlow { /// any fragments it is responsible for flowing. /// /// TODO(pcwalton): Inline blocks. - fn bubble_inline_sizes(&mut self, _: &LayoutContext) { + fn bubble_inline_sizes(&mut self, layout_context: &LayoutContext) { let _scope = layout_debug_scope!("block::bubble_inline_sizes {:s}", self.base.debug_id()); let mut flags = self.base.flags; @@ -1572,7 +1572,7 @@ impl Flow for BlockFlow { max(intrinsic_inline_sizes.preferred_inline_size, left_float_width + right_float_width); - let fragment_intrinsic_inline_sizes = self.fragment.intrinsic_inline_sizes(); + let fragment_intrinsic_inline_sizes = self.fragment.intrinsic_inline_sizes(layout_context); intrinsic_inline_sizes.minimum_inline_size = max(intrinsic_inline_sizes.minimum_inline_size, fragment_intrinsic_inline_sizes.minimum_inline_size); intrinsic_inline_sizes.preferred_inline_size = max(intrinsic_inline_sizes.preferred_inline_size, diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 755f39582f9..818fa1602e6 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -27,12 +27,12 @@ use flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use flow::{Descendants, AbsDescendants}; use flow; use flow_ref::FlowRef; -use fragment::{InlineBlockFragment, InlineBlockFragmentInfo}; +use fragment::{InlineBlockFragment, InlineBlockFragmentInfo, InputFragment}; use fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo}; use fragment::{ImageFragment, ImageFragmentInfo, SpecificFragmentInfo, TableFragment}; use fragment::{TableCellFragment, TableColumnFragment, TableColumnFragmentInfo}; use fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment}; -use fragment::{UnscannedTextFragmentInfo}; +use fragment::{UnscannedTextFragmentInfo, InputFragmentInfo}; use inline::{InlineFragments, InlineFlow}; use parallel; use table_wrapper::TableWrapperFlow; @@ -49,7 +49,7 @@ use wrapper::{Before, After, Normal}; use gfx::display_list::OpaqueNode; use script::dom::element::{HTMLIFrameElementTypeId, HTMLImageElementTypeId}; -use script::dom::element::{HTMLObjectElementTypeId}; +use script::dom::element::{HTMLObjectElementTypeId, HTMLInputElementTypeId}; use script::dom::element::{HTMLTableColElementTypeId, HTMLTableDataCellElementTypeId}; use script::dom::element::{HTMLTableElementTypeId, HTMLTableHeaderCellElementTypeId}; use script::dom::element::{HTMLTableRowElementTypeId, HTMLTableSectionElementTypeId}; @@ -221,6 +221,21 @@ impl<'a> FlowConstructor<'a> { } } + fn build_fragment_info_for_input(&mut self, node: &ThreadSafeLayoutNode) -> SpecificFragmentInfo { + //FIXME: would it make more sense to use HTMLInputElement::input_type instead of the raw + // value? definitely for string comparisons. + let elem = node.as_element(); + let data = match elem.get_attr(&ns!(""), "type") { + Some("checkbox") | Some("radio") => None, + Some("button") | Some("submit") | Some("reset") => + Some(node.get_input_value().len() as u32), + Some("file") => Some(node.get_input_size()), + _ => Some(node.get_input_size()), + }; + data.map(|size| InputFragment(InputFragmentInfo { size: size })) + .unwrap_or(GenericFragment) + } + /// Builds specific `Fragment` info for the given node. /// /// This does *not* construct the text for generated content (but, for generated content with @@ -230,11 +245,14 @@ impl<'a> FlowConstructor<'a> { pub fn build_specific_fragment_info_for_node(&mut self, node: &ThreadSafeLayoutNode) -> SpecificFragmentInfo { match node.type_id() { + Some(ElementNodeTypeId(HTMLIFrameElementTypeId)) => { + IframeFragment(IframeFragmentInfo::new(node)) + } Some(ElementNodeTypeId(HTMLImageElementTypeId)) => { self.build_fragment_info_for_image(node, node.image_url()) } - Some(ElementNodeTypeId(HTMLIFrameElementTypeId)) => { - IframeFragment(IframeFragmentInfo::new(node)) + Some(ElementNodeTypeId(HTMLInputElementTypeId)) => { + self.build_fragment_info_for_input(node) } Some(ElementNodeTypeId(HTMLObjectElementTypeId)) => { let data = node.get_object_data(); @@ -445,7 +463,8 @@ impl<'a> FlowConstructor<'a> { // Special case: If this is generated content, then we need to initialize the accumulator // with the fragment corresponding to that content. - if node.get_pseudo_element_type() != Normal { + if node.get_pseudo_element_type() != Normal || + node.type_id() == Some(ElementNodeTypeId(HTMLInputElementTypeId)) { let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)); let mut fragment = Fragment::new_from_specific_info(node, fragment_info); inline_fragment_accumulator.fragments.push(&mut fragment); diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 59c256022bb..7c2ef5c4a05 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -128,10 +128,11 @@ impl<E, S: Encoder<E>> Encodable<S, E> for Fragment { /// Info specific to the kind of fragment. Keep this enum small. #[deriving(Clone)] pub enum SpecificFragmentInfo { - InlineBlockFragment(InlineBlockFragmentInfo), GenericFragment, - ImageFragment(ImageFragmentInfo), IframeFragment(IframeFragmentInfo), + ImageFragment(ImageFragmentInfo), + InlineBlockFragment(InlineBlockFragmentInfo), + InputFragment(InputFragmentInfo), ScannedTextFragment(ScannedTextFragmentInfo), TableFragment, TableCellFragment, @@ -155,6 +156,22 @@ impl InlineBlockFragmentInfo { } } +/// A fragment that represents a displayable form element +#[deriving(Clone)] +pub struct InputFragmentInfo { + pub size: u32, +} + +impl InputFragmentInfo { + /// Returns the original inline-size of the input. + fn input_inline_size(&self, font_style: &FontStyle, layout_context: &LayoutContext) -> Au { + let metrics = text::font_metrics_for_style(layout_context.font_context(), font_style); + + // https://html.spec.whatwg.org/#converting-a-character-width-to-pixels + metrics.average_advance * (self.size as i32 - 1) + metrics.max_advance + } +} + /// A fragment that represents a replaced content image and its accompanying borders, shadows, etc. #[deriving(Clone)] pub struct ImageFragmentInfo { @@ -499,7 +516,8 @@ impl Fragment { /// replaced elements. fn style_specified_intrinsic_inline_size(&self) -> IntrinsicISizes { let (use_margins, use_padding) = match self.specific { - GenericFragment | IframeFragment(_) | ImageFragment(_) | InlineBlockFragment(_) => (true, true), + GenericFragment | IframeFragment(_) | ImageFragment(_) | InlineBlockFragment(_) | + InputFragment(_) => (true, true), TableFragment | TableCellFragment => (false, true), TableWrapperFragment => (true, false), TableRowFragment => (false, false), @@ -1129,7 +1147,7 @@ impl Fragment { text_fragment)) } GenericFragment | IframeFragment(..) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) => { + TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) => { // FIXME(pcwalton): This is a bit of an abuse of the logging infrastructure. We // should have a real `SERVO_DEBUG` system. debug!("{:?}", self.build_debug_borders_around_fragment(display_list, flow_origin)) @@ -1193,7 +1211,7 @@ impl Fragment { } /// Returns the intrinsic inline-sizes of this fragment. - pub fn intrinsic_inline_sizes(&mut self) -> IntrinsicISizes { + pub fn intrinsic_inline_sizes(&mut self, layout_context: &LayoutContext) -> IntrinsicISizes { let mut result = self.style_specified_intrinsic_inline_size(); match self.specific { @@ -1214,6 +1232,12 @@ impl Fragment { result.preferred_inline_size = max(result.preferred_inline_size, image_inline_size); } + InputFragment(ref input_fragment_info) => { + let font_style = text::computed_style_to_font_style(&*self.style); + let input_inline_size = input_fragment_info.input_inline_size(&font_style, layout_context); + result.minimum_inline_size = input_inline_size; + result.preferred_inline_size = input_inline_size; + } ScannedTextFragment(ref text_fragment_info) => { let range = &text_fragment_info.range; let min_line_inline_size = text_fragment_info.run.min_width_for_range(range); @@ -1260,7 +1284,7 @@ impl Fragment { pub fn content_inline_size(&self) -> Au { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | TableRowFragment | - TableWrapperFragment | InlineBlockFragment(_) => Au(0), + TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) => Au(0), ImageFragment(ref image_fragment_info) => { image_fragment_info.computed_inline_size() } @@ -1278,7 +1302,8 @@ impl Fragment { pub fn content_block_size(&self, layout_context: &LayoutContext) -> Au { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) => Au(0), + TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | + InputFragment(_) => Au(0), ImageFragment(ref image_fragment_info) => { image_fragment_info.computed_block_size() } @@ -1312,7 +1337,7 @@ impl Fragment { -> Option<(SplitInfo, Option<SplitInfo>, Arc<Box<TextRun>> /* TODO(bjz): remove */)> { match self.specific { GenericFragment | IframeFragment(_) | ImageFragment(_) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment => None, + TableRowFragment | TableWrapperFragment | InputFragment(_) => None, TableColumnFragment(_) => fail!("Table column fragments do not need to split"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), InlineBlockFragment(_) => fail!("Inline blocks do not get split"), @@ -1353,7 +1378,7 @@ impl Fragment { -> Option<(Option<SplitInfo>, Option<SplitInfo>, Arc<Box<TextRun>> /* TODO(bjz): remove */)> { match self.specific { GenericFragment | IframeFragment(_) | ImageFragment(_) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) => None, + TableRowFragment | TableWrapperFragment | InlineBlockFragment(_) | InputFragment(_) => None, TableColumnFragment(_) => fail!("Table column fragments do not have inline_size"), UnscannedTextFragment(_) => fail!("Unscanned text fragments should have been scanned by now!"), ScannedTextFragment(ref text_fragment_info) => { @@ -1457,7 +1482,7 @@ impl Fragment { container_inline_size: Au) { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment => return, + TableRowFragment | TableWrapperFragment | InputFragment(_) => return, TableColumnFragment(_) => fail!("Table column fragments do not have inline_size"), UnscannedTextFragment(_) => { fail!("Unscanned text fragments should have been scanned by now!") @@ -1540,7 +1565,7 @@ impl Fragment { pub fn assign_replaced_block_size_if_necessary(&mut self) { match self.specific { GenericFragment | IframeFragment(_) | TableFragment | TableCellFragment | - TableRowFragment | TableWrapperFragment => return, + TableRowFragment | TableWrapperFragment | InputFragment(_) => return, TableColumnFragment(_) => fail!("Table column fragments do not have block_size"), UnscannedTextFragment(_) => { fail!("Unscanned text fragments should have been scanned by now!") @@ -1682,7 +1707,7 @@ impl Fragment { InlineBlockFragment(_) | TableWrapperFragment => false, GenericFragment | IframeFragment(_) | ImageFragment(_) | ScannedTextFragment(_) | TableFragment | TableCellFragment | TableColumnFragment(_) | TableRowFragment | - UnscannedTextFragment(_) => true, + UnscannedTextFragment(_) | InputFragment(_) => true, } } } @@ -1703,6 +1728,7 @@ impl fmt::Show for Fragment { TableWrapperFragment => "TableWrapperFragment", UnscannedTextFragment(_) => "UnscannedTextFragment", InlineBlockFragment(_) => "InlineBlockFragment", + InputFragment(_) => "InputFragment", })); try!(write!(f, "bp {}", self.border_padding)); try!(write!(f, " ")); diff --git a/components/layout/inline.rs b/components/layout/inline.rs index a683c8574c9..d937a6cef53 100644 --- a/components/layout/inline.rs +++ b/components/layout/inline.rs @@ -955,7 +955,7 @@ impl Flow for InlineFlow { self } - fn bubble_inline_sizes(&mut self, _: &LayoutContext) { + fn bubble_inline_sizes(&mut self, layout_context: &LayoutContext) { let _scope = layout_debug_scope!("inline::bubble_inline_sizes {:s}", self.base.debug_id()); let writing_mode = self.base.writing_mode; @@ -968,7 +968,7 @@ impl Flow for InlineFlow { debug!("Flow: measuring {}", *fragment); let fragment_intrinsic_inline_sizes = - fragment.intrinsic_inline_sizes(); + fragment.intrinsic_inline_sizes(layout_context); intrinsic_inline_sizes.minimum_inline_size = max( intrinsic_inline_sizes.minimum_inline_size, fragment_intrinsic_inline_sizes.minimum_inline_size); diff --git a/components/layout/table.rs b/components/layout/table.rs index d48b845bc98..92e069f1c5c 100644 --- a/components/layout/table.rs +++ b/components/layout/table.rs @@ -171,7 +171,7 @@ impl Flow for TableFlow { /// table layout calculation. /// The maximum min/pref inline-sizes of each column are set from the rows for the automatic /// table layout calculation. - fn bubble_inline_sizes(&mut self, _: &LayoutContext) { + fn bubble_inline_sizes(&mut self, layout_context: &LayoutContext) { let _scope = layout_debug_scope!("table::bubble_inline_sizes {:s}", self.block_flow.base.debug_id()); @@ -239,7 +239,8 @@ impl Flow for TableFlow { } } - let fragment_intrinsic_inline_sizes = self.block_flow.fragment.intrinsic_inline_sizes(); + let fragment_intrinsic_inline_sizes = + self.block_flow.fragment.intrinsic_inline_sizes(layout_context); self.block_flow.base.intrinsic_inline_sizes.minimum_inline_size = min_inline_size; self.block_flow.base.intrinsic_inline_sizes.preferred_inline_size = max(min_inline_size, pref_inline_size); diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 18fd74fca9b..eb1be0b09de 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -36,13 +36,14 @@ use css::node_style::StyledNode; use util::{LayoutDataAccess, LayoutDataWrapper, PrivateLayoutData}; -use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived}; +use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived, HTMLInputElementDerived}; use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived}; use script::dom::bindings::js::JS; use script::dom::element::{Element, HTMLAreaElementTypeId, HTMLAnchorElementTypeId}; use script::dom::element::{HTMLLinkElementTypeId, LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::htmliframeelement::HTMLIFrameElement; use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; +use script::dom::htmlinputelement::{HTMLInputElement, LayoutHTMLInputElementHelpers}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId}; use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, SharedLayoutData, TextNodeTypeId}; use script::dom::text::Text; @@ -184,11 +185,15 @@ impl<'ln> TLayoutNode for LayoutNode<'ln> { fn text(&self) -> String { unsafe { - if !self.get().is_text() { + if self.get().is_text() { + let text: JS<Text> = self.get_jsmanaged().transmute_copy(); + (*text.unsafe_get()).characterdata.data.deref().borrow().clone() + } else if self.get().is_htmlinputelement() { + let input: JS<HTMLInputElement> = self.get_jsmanaged().transmute_copy(); + input.get_value_for_layout() + } else { fail!("not text!") } - let text: JS<Text> = self.get_jsmanaged().transmute_copy(); - (*text.unsafe_get()).characterdata.data.deref().borrow().clone() } } } @@ -567,14 +572,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { return get_content(&after_style.get_box().content) } } - - unsafe { - if !self.get().is_text() { - fail!("not text!") - } - let text: JS<Text> = self.get_jsmanaged().transmute_copy(); - (*text.unsafe_get()).characterdata.data.deref().borrow().clone() - } + self.node.text() } } @@ -732,6 +730,26 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { _ => false } } + + pub fn get_input_value(&self) -> String { + unsafe { + if !self.get().is_htmlinputelement() { + fail!("not an input element!") + } + let input: JS<HTMLInputElement> = self.get_jsmanaged().transmute_copy(); + input.get_value_for_layout() + } + } + + pub fn get_input_size(&self) -> u32 { + unsafe { + if !self.get().is_htmlinputelement() { + fail!("not an input element!") + } + let input: JS<HTMLInputElement> = self.get_jsmanaged().transmute_copy(); + input.get_size_for_layout() + } + } } pub struct ThreadSafeLayoutNodeChildrenIterator<'a> { |