Implement simple layout for text, button, radio, and checkbox inputs. Implement simple interaction for checkboxes and radio buttons.

This commit is contained in:
Josh Matthews 2014-09-29 02:59:39 -04:00
parent 9b20d6e7d2
commit f70bb68503
10 changed files with 422 additions and 50 deletions

View file

@ -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,38 @@ impl InlineBlockFragmentInfo {
}
}
/// A fragment that represents a displayable form element
#[deriving(Clone)]
pub enum InputFragmentInfo {
InputButton(u32),
InputText(u32),
InputCheckbox(bool),
InputRadioButton(bool),
InputFile(u32),
}
impl InputFragmentInfo {
fn size(&self) -> Option<u32> {
match self {
&InputText(size) | &InputFile(size) | &InputButton(size) => Some(size),
_ => None,
}
}
/// Returns the original inline-size of the input.
fn input_inline_size(&self, font_style: &FontStyle, layout_context: &LayoutContext) -> Au {
match self.size() {
Some(size) => {
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 * (size as i32 - 1) + metrics.max_advance
}
None => Au::from_px(10)
}
}
}
/// A fragment that represents a replaced content image and its accompanying borders, shadows, etc.
#[deriving(Clone)]
pub struct ImageFragmentInfo {
@ -499,7 +532,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 +1163,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 +1227,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 +1248,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 +1300,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 +1318,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 +1353,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 +1394,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 +1498,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 +1581,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 +1723,7 @@ impl Fragment {
InlineBlockFragment(_) | TableWrapperFragment => false,
GenericFragment | IframeFragment(_) | ImageFragment(_) | ScannedTextFragment(_) |
TableFragment | TableCellFragment | TableColumnFragment(_) | TableRowFragment |
UnscannedTextFragment(_) => true,
UnscannedTextFragment(_) | InputFragment(_) => true,
}
}
}
@ -1703,6 +1744,7 @@ impl fmt::Show for Fragment {
TableWrapperFragment => "TableWrapperFragment",
UnscannedTextFragment(_) => "UnscannedTextFragment",
InlineBlockFragment(_) => "InlineBlockFragment",
InputFragment(_) => "InputFragment",
}));
try!(write!(f, "bp {}", self.border_padding));
try!(write!(f, " "));