diff --git a/src/servo/layout/box.rs b/src/servo/layout/box.rs index 9bc9ddb28b9..5499e9ae1e2 100644 --- a/src/servo/layout/box.rs +++ b/src/servo/layout/box.rs @@ -115,7 +115,7 @@ trait RenderBoxMethods { pure fn content_box() -> Rect; pure fn border_box() -> Rect; - fn split_to_width(@self, &LayoutContext, au) -> SplitBoxResult; + fn split_to_width(@self, &LayoutContext, au, starts_line: bool) -> SplitBoxResult; fn get_min_width(&LayoutContext) -> au; fn get_pref_width(&LayoutContext) -> au; fn get_used_width() -> (au, au); @@ -176,16 +176,67 @@ impl RenderBox : RenderBoxMethods { } } - fn split_to_width(@self, _ctx: &LayoutContext, _max_width: au) -> SplitBoxResult { - // TODO: finish - CannotSplit(self) -/* match self { + fn split_to_width(@self, _ctx: &LayoutContext, max_width: au, starts_line: bool) -> SplitBoxResult { + match self { @GenericBox(*) => CannotSplit(self), @ImageBox(*) => CannotSplit(self), - @TextBox(*) => { - } + @UnscannedTextBox(*) => fail ~"WAT: shouldn't be an unscanned text box here.", + @TextBox(_,data) => { + + let mut i : uint = 0; + let mut remaining_width : au = max_width; + let mut left_offset : uint = data.offset; + let mut left_length : uint = 0; + let mut right_offset : Option = None; + let mut right_length : Option = None; + do data.run.iter_indivisible_pieces_for_range(data.offset, data.length) |off, len| { + let metrics = data.run.metrics_for_range(off, len); + let advance = metrics.advance_width; + let should_continue : bool; + + if advance < remaining_width { + if starts_line && data.run.range_is_trimmable_whitespace(off, len) { + left_offset += len; + } else { + remaining_width -= advance; + left_length += len; + } + should_continue = true; + } else if advance > remaining_width + && data.run.range_is_trimmable_whitespace(off, len) { + // if there are still things after the trimmable whitespace, create right chunk + if off + len < data.length { + right_offset = Some(off + len); + right_length = Some(data.length - (off + len)); + } + should_continue = false; + } else { + right_offset = Some(off); + right_length = Some(data.length - off); + should_continue = false; + } + + i += 1; + should_continue + } + + assert left_length > 0; + let left_box = layout::text::adapt_textbox_with_range(self.d(), data.run, + left_offset, left_length); + + match (right_offset, right_length) { + (Some(right_off), Some(right_len)) => { + assert right_len > 0; + let right_box = layout::text::adapt_textbox_with_range(self.d(), data.run, + right_off, right_len); + if i == 1 { return SplitDidNotFit(left_box, right_box); } + else { return SplitDidFit(left_box, right_box); } + }, + (None, None) => { return SplitUnnecessary(left_box); }, + (_, _) => fail ~"Must specify right box's offset and length, not one or other." + } + }, } -*/ } /** In general, these functions are transitively impure because they diff --git a/src/servo/text/text_run.rs b/src/servo/text/text_run.rs index 5e5348bbf28..dc42219c65a 100644 --- a/src/servo/text/text_run.rs +++ b/src/servo/text/text_run.rs @@ -48,6 +48,9 @@ pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun { trait TextRunMethods { pure fn glyphs(&self) -> &self/GlyphStore; pure fn iter_indivisible_pieces_for_range(&self, offset: uint, length: uint, f: fn(uint, uint) -> bool); + // TODO: needs to take box style as argument, or move to TextBox. + // see Gecko's IsTrimmableSpace methods for details. + pure fn range_is_trimmable_whitespace(&self, offset: uint, length: uint) -> bool; fn metrics_for_range(offset: uint, length: uint) -> RunMetrics; fn min_width_for_range(offset: uint, length: uint) -> au; @@ -57,6 +60,19 @@ trait TextRunMethods { impl TextRun : TextRunMethods { pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs } + pure fn range_is_trimmable_whitespace(&self, offset: uint, length: uint) -> bool { + let mut i = offset; + while i < offset + length { + let {ch, next} = str::char_range_at(self.text, i); + match ch { + ' ' | '\t' | '\r' => {}, + _ => { return false; } + } + i = next; + } + return true; + } + fn metrics_for_range(offset: uint, length: uint) -> RunMetrics { self.font.measure_text(&self, offset, length) }