mirror of
https://github.com/servo/servo.git
synced 2025-08-11 16:35:33 +01:00
Implement TextRunScanner; add explicit @self to all flow-related functions.
This commit is contained in:
parent
2bc9e66257
commit
26d5cfb509
9 changed files with 221 additions and 67 deletions
|
@ -24,11 +24,11 @@ trait BlockLayout {
|
||||||
pure fn starts_block_flow() -> bool;
|
pure fn starts_block_flow() -> bool;
|
||||||
pure fn with_block_box(fn(box: &@RenderBox) -> ()) -> ();
|
pure fn with_block_box(fn(box: &@RenderBox) -> ()) -> ();
|
||||||
|
|
||||||
fn bubble_widths_block(ctx: &LayoutContext);
|
fn bubble_widths_block(@self, ctx: &LayoutContext);
|
||||||
fn assign_widths_block(ctx: &LayoutContext);
|
fn assign_widths_block(@self, ctx: &LayoutContext);
|
||||||
fn assign_height_block(ctx: &LayoutContext);
|
fn assign_height_block(@self, ctx: &LayoutContext);
|
||||||
|
|
||||||
fn build_display_list_block(a: &dl::DisplayListBuilder, b: &Rect<au>,
|
fn build_display_list_block(@self, a: &dl::DisplayListBuilder, b: &Rect<au>,
|
||||||
c: &Point2D<au>, d: &dl::DisplayList);
|
c: &Point2D<au>, d: &dl::DisplayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,14 +66,14 @@ impl FlowContext : BlockLayout {
|
||||||
/* TODO: floats */
|
/* TODO: floats */
|
||||||
/* TODO: absolute contexts */
|
/* TODO: absolute contexts */
|
||||||
/* TODO: inline-blocks */
|
/* TODO: inline-blocks */
|
||||||
fn bubble_widths_block(ctx: &LayoutContext) {
|
fn bubble_widths_block(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_block_flow();
|
assert self.starts_block_flow();
|
||||||
|
|
||||||
let mut min_width = au(0);
|
let mut min_width = au(0);
|
||||||
let mut pref_width = au(0);
|
let mut pref_width = au(0);
|
||||||
|
|
||||||
/* find max width from child block contexts */
|
/* find max width from child block contexts */
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(self) |child_ctx| {
|
||||||
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
||||||
|
|
||||||
min_width = au::max(min_width, child_ctx.d().min_width);
|
min_width = au::max(min_width, child_ctx.d().min_width);
|
||||||
|
@ -98,7 +98,7 @@ impl FlowContext : BlockLayout {
|
||||||
Dual boxes consume some width first, and the remainder is assigned to
|
Dual boxes consume some width first, and the remainder is assigned to
|
||||||
all child (block) contexts. */
|
all child (block) contexts. */
|
||||||
|
|
||||||
fn assign_widths_block(_ctx: &LayoutContext) {
|
fn assign_widths_block(@self, _ctx: &LayoutContext) {
|
||||||
assert self.starts_block_flow();
|
assert self.starts_block_flow();
|
||||||
|
|
||||||
let mut remaining_width = self.d().position.size.width;
|
let mut remaining_width = self.d().position.size.width;
|
||||||
|
@ -113,19 +113,19 @@ impl FlowContext : BlockLayout {
|
||||||
remaining_width = remaining_width.sub(&left_used.add(&right_used));
|
remaining_width = remaining_width.sub(&left_used.add(&right_used));
|
||||||
}
|
}
|
||||||
|
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(self) |child_ctx| {
|
||||||
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
assert child_ctx.starts_block_flow() || child_ctx.starts_inline_flow();
|
||||||
child_ctx.d().position.origin.x = left_used;
|
child_ctx.d().position.origin.x = left_used;
|
||||||
child_ctx.d().position.size.width = remaining_width;
|
child_ctx.d().position.size.width = remaining_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height_block(_ctx: &LayoutContext) {
|
fn assign_height_block(@self, _ctx: &LayoutContext) {
|
||||||
assert self.starts_block_flow();
|
assert self.starts_block_flow();
|
||||||
|
|
||||||
let mut cur_y = au(0);
|
let mut cur_y = au(0);
|
||||||
|
|
||||||
for FlowTree.each_child(@self) |child_ctx| {
|
for FlowTree.each_child(self) |child_ctx| {
|
||||||
child_ctx.d().position.origin.y = cur_y;
|
child_ctx.d().position.origin.y = cur_y;
|
||||||
cur_y = cur_y.add(&child_ctx.d().position.size.height);
|
cur_y = cur_y.add(&child_ctx.d().position.size.height);
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ impl FlowContext : BlockLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_block(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
fn build_display_list_block(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
|
|
||||||
assert self.starts_block_flow();
|
assert self.starts_block_flow();
|
||||||
|
@ -155,7 +155,7 @@ impl FlowContext : BlockLayout {
|
||||||
// TODO: handle any out-of-flow elements
|
// TODO: handle any out-of-flow elements
|
||||||
|
|
||||||
// go deeper into the flow tree
|
// go deeper into the flow tree
|
||||||
for FlowTree.each_child(@self) |child| {
|
for FlowTree.each_child(self) |child| {
|
||||||
self.build_display_list_for_child(builder, child, dirty, offset, list)
|
self.build_display_list_for_child(builder, child, dirty, offset, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct RenderBoxData {
|
||||||
enum RenderBoxType {
|
enum RenderBoxType {
|
||||||
RenderBox_Generic,
|
RenderBox_Generic,
|
||||||
RenderBox_Image,
|
RenderBox_Image,
|
||||||
RenderBox_Text
|
RenderBox_Text,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum RenderBox {
|
pub enum RenderBox {
|
||||||
|
@ -101,6 +101,8 @@ trait RenderBoxMethods {
|
||||||
pure fn d(&self) -> &self/RenderBoxData;
|
pure fn d(&self) -> &self/RenderBoxData;
|
||||||
|
|
||||||
pure fn is_replaced() -> bool;
|
pure fn is_replaced() -> bool;
|
||||||
|
pure fn can_split() -> bool;
|
||||||
|
pure fn can_merge_with_box(@self, other: @RenderBox) -> bool;
|
||||||
pure fn content_box() -> Rect<au>;
|
pure fn content_box() -> Rect<au>;
|
||||||
pure fn border_box() -> Rect<au>;
|
pure fn border_box() -> Rect<au>;
|
||||||
|
|
||||||
|
@ -141,6 +143,23 @@ impl RenderBox : RenderBoxMethods {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pure fn can_split() -> bool {
|
||||||
|
match self {
|
||||||
|
TextBox(*) => true,
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pure fn can_merge_with_box(@self, other: @RenderBox) -> bool {
|
||||||
|
assert !core::box::ptr_eq(self, other);
|
||||||
|
|
||||||
|
match (self, other) {
|
||||||
|
(@UnscannedTextBox(*), @UnscannedTextBox(*)) => true,
|
||||||
|
(@TextBox(_,d1), @TextBox(_,d2)) => { core::box::ptr_eq(d1.run, d2.run) }
|
||||||
|
(_, _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** In general, these functions are transitively impure because they
|
/** In general, these functions are transitively impure because they
|
||||||
* may cause glyphs to be allocated. For now, it's impure because of
|
* may cause glyphs to be allocated. For now, it's impure because of
|
||||||
* holder.get_image()
|
* holder.get_image()
|
||||||
|
|
|
@ -32,19 +32,19 @@ pub struct DisplayListBuilder {
|
||||||
|
|
||||||
|
|
||||||
trait FlowDisplayListBuilderMethods {
|
trait FlowDisplayListBuilderMethods {
|
||||||
fn build_display_list(a: &DisplayListBuilder, b: &Rect<au>, c: &dl::DisplayList);
|
fn build_display_list(@self, a: &DisplayListBuilder, b: &Rect<au>, c: &dl::DisplayList);
|
||||||
|
|
||||||
fn build_display_list_for_child(a: &DisplayListBuilder, b: @FlowContext,
|
fn build_display_list_for_child(@self, a: &DisplayListBuilder, b: @FlowContext,
|
||||||
c: &Rect<au>, d: &Point2D<au>, e: &dl::DisplayList);
|
c: &Rect<au>, d: &Point2D<au>, e: &dl::DisplayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowContext: FlowDisplayListBuilderMethods {
|
impl FlowContext: FlowDisplayListBuilderMethods {
|
||||||
fn build_display_list(builder: &DisplayListBuilder, dirty: &Rect<au>, list: &dl::DisplayList) {
|
fn build_display_list(@self, builder: &DisplayListBuilder, dirty: &Rect<au>, list: &dl::DisplayList) {
|
||||||
let zero = au::zero_point();
|
let zero = au::zero_point();
|
||||||
self.build_display_list_recurse(builder, dirty, &zero, list);
|
self.build_display_list_recurse(builder, dirty, &zero, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_for_child(builder: &DisplayListBuilder, child: @FlowContext,
|
fn build_display_list_for_child(@self, builder: &DisplayListBuilder, child: @FlowContext,
|
||||||
dirty: &Rect<au>, offset: &Point2D<au>,
|
dirty: &Rect<au>, offset: &Point2D<au>,
|
||||||
list: &dl::DisplayList) {
|
list: &dl::DisplayList) {
|
||||||
|
|
||||||
|
|
|
@ -130,39 +130,39 @@ fn FlowData(id: int) -> FlowData {
|
||||||
|
|
||||||
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
||||||
impl FlowContext {
|
impl FlowContext {
|
||||||
fn bubble_widths(ctx: &LayoutContext) {
|
fn bubble_widths(@self, ctx: &LayoutContext) {
|
||||||
match self {
|
match self {
|
||||||
BlockFlow(*) => self.bubble_widths_block(ctx),
|
@BlockFlow(*) => self.bubble_widths_block(ctx),
|
||||||
InlineFlow(*) => self.bubble_widths_inline(ctx),
|
@InlineFlow(*) => self.bubble_widths_inline(ctx),
|
||||||
RootFlow(*) => self.bubble_widths_root(ctx),
|
@RootFlow(*) => self.bubble_widths_root(ctx),
|
||||||
_ => fail fmt!("Tried to bubble_widths of flow: %?", self)
|
_ => fail fmt!("Tried to bubble_widths of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_widths(ctx: &LayoutContext) {
|
fn assign_widths(@self, ctx: &LayoutContext) {
|
||||||
match self {
|
match self {
|
||||||
BlockFlow(*) => self.assign_widths_block(ctx),
|
@BlockFlow(*) => self.assign_widths_block(ctx),
|
||||||
InlineFlow(*) => self.assign_widths_inline(ctx),
|
@InlineFlow(*) => self.assign_widths_inline(ctx),
|
||||||
RootFlow(*) => self.assign_widths_root(ctx),
|
@RootFlow(*) => self.assign_widths_root(ctx),
|
||||||
_ => fail fmt!("Tried to assign_widths of flow: %?", self)
|
_ => fail fmt!("Tried to assign_widths of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height(ctx: &LayoutContext) {
|
fn assign_height(@self, ctx: &LayoutContext) {
|
||||||
match self {
|
match self {
|
||||||
BlockFlow(*) => self.assign_height_block(ctx),
|
@BlockFlow(*) => self.assign_height_block(ctx),
|
||||||
InlineFlow(*) => self.assign_height_inline(ctx),
|
@InlineFlow(*) => self.assign_height_inline(ctx),
|
||||||
RootFlow(*) => self.assign_height_root(ctx),
|
@RootFlow(*) => self.assign_height_root(ctx),
|
||||||
_ => fail fmt!("Tried to assign_height of flow: %?", self)
|
_ => fail fmt!("Tried to assign_height of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_recurse(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
fn build_display_list_recurse(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
match self {
|
match self {
|
||||||
RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
@RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
||||||
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
@BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
||||||
InlineFlow(*) => self.build_display_list_inline(builder, dirty, offset, list),
|
@InlineFlow(*) => self.build_display_list_inline(builder, dirty, offset, list),
|
||||||
_ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self)
|
_ => fail fmt!("Tried to build_display_list_recurse of flow: %?", self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@ use std::arc;
|
||||||
use util::tree;
|
use util::tree;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tentative design: (may not line up with reality)
|
|
||||||
|
|
||||||
Lineboxes are represented as offsets into the child list, rather than
|
Lineboxes are represented as offsets into the child list, rather than
|
||||||
as an object that "owns" boxes. Choosing a different set of line
|
as an object that "owns" boxes. Choosing a different set of line
|
||||||
breaks requires a new list of offsets, and possibly some splitting and
|
breaks requires a new list of offsets, and possibly some splitting and
|
||||||
|
@ -43,17 +41,129 @@ hard to try out that alternative.
|
||||||
|
|
||||||
type BoxRange = {start: u8, len: u8};
|
type BoxRange = {start: u8, len: u8};
|
||||||
|
|
||||||
// TODO: flesh out into TextRunScanner
|
// stack-allocated object for scanning an inline flow into
|
||||||
fn build_runs_for_flow(ctx: &LayoutContext, dummy_boxes: &DVec<@RenderBox>) {
|
// TextRun-containing TextBoxes.
|
||||||
for uint::range(0, dummy_boxes.len()) |i| {
|
struct TextRunScanner {
|
||||||
match *dummy_boxes[i] {
|
mut in_clump: bool,
|
||||||
UnscannedTextBox(d, text) => {
|
mut clump_start: uint,
|
||||||
|
mut clump_end: uint,
|
||||||
|
flow: @FlowContext,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn TextRunScanner(flow: @FlowContext) -> TextRunScanner {
|
||||||
|
TextRunScanner {
|
||||||
|
in_clump: false,
|
||||||
|
clump_start: 0,
|
||||||
|
clump_end: 0,
|
||||||
|
flow: flow,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TextRunScanner {
|
||||||
|
fn scan_for_runs(ctx: &LayoutContext) {
|
||||||
|
// if reused, must be reset.
|
||||||
|
assert !self.in_clump;
|
||||||
|
let in_boxes = self.flow.inline().boxes;
|
||||||
|
assert in_boxes.len() > 0;
|
||||||
|
|
||||||
|
debug!("scanning %u boxes for text runs...", in_boxes.len());
|
||||||
|
|
||||||
|
let temp_boxes = DVec();
|
||||||
|
let mut prev_box: @RenderBox = in_boxes[0];
|
||||||
|
|
||||||
|
for uint::range(0, in_boxes.len()) |i| {
|
||||||
|
debug!("considering box: %?", in_boxes[i].debug_str());
|
||||||
|
|
||||||
|
let can_coalesce_with_prev = i > 0 && boxes_can_be_coalesced(prev_box, in_boxes[i]);
|
||||||
|
|
||||||
|
match (self.in_clump, can_coalesce_with_prev) {
|
||||||
|
// start a new clump
|
||||||
|
(false, _) => { self.reset_clump_to_index(i); },
|
||||||
|
// extend clump
|
||||||
|
(true, true) => { self.clump_end = i; },
|
||||||
|
// boundary detected; flush and start new clump
|
||||||
|
(true, false) => {
|
||||||
|
self.flush_clump_to_list(ctx, &temp_boxes);
|
||||||
|
self.reset_clump_to_index(i);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
prev_box = in_boxes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle remaining clumps
|
||||||
|
if self.in_clump {
|
||||||
|
self.flush_clump_to_list(ctx, &temp_boxes);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("swapping out boxes.");
|
||||||
|
// swap out old and new box list of flow
|
||||||
|
self.flow.inline().boxes.set(dvec::unwrap(temp_boxes));
|
||||||
|
|
||||||
|
debug!("new inline flow boxes:");
|
||||||
|
do self.flow.inline().boxes.each |box| {
|
||||||
|
debug!("%s", box.debug_str()); true
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper functions
|
||||||
|
pure fn boxes_can_be_coalesced(a: @RenderBox, b: @RenderBox) -> bool {
|
||||||
|
assert !core::box::ptr_eq(a, b);
|
||||||
|
|
||||||
|
match (a, b) {
|
||||||
|
// TODO: check whether text styles, fonts are the same.
|
||||||
|
(@UnscannedTextBox(*), @UnscannedTextBox(*)) => a.can_merge_with_box(b),
|
||||||
|
(_, _) => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_clump_to_index(i: uint) {
|
||||||
|
debug!("resetting clump to %u", i);
|
||||||
|
|
||||||
|
self.clump_start = i;
|
||||||
|
self.clump_end = i;
|
||||||
|
self.in_clump = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_clump_to_list(ctx: &LayoutContext, temp_boxes: &DVec<@RenderBox>) {
|
||||||
|
assert self.in_clump;
|
||||||
|
|
||||||
|
debug!("flushing when start=%?,end=%?", self.clump_start, self.clump_end);
|
||||||
|
|
||||||
|
let in_boxes = self.flow.inline().boxes;
|
||||||
|
let is_singleton = (self.clump_start == self.clump_end);
|
||||||
|
let is_text_clump = match in_boxes[self.clump_start] {
|
||||||
|
@UnscannedTextBox(*) => true,
|
||||||
|
_ => false
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: repair the mapping of DOM elements to boxes if it changed.
|
||||||
|
// (the mapping does not yet exist; see Issue #103)
|
||||||
|
match (is_singleton, is_text_clump) {
|
||||||
|
(false, false) => fail ~"WAT: can't coalesce non-text boxes in flush_clump_to_list()!",
|
||||||
|
(true, false) => { temp_boxes.push(in_boxes[self.clump_start]); }
|
||||||
|
(true, true) => {
|
||||||
|
let text = in_boxes[self.clump_start].raw_text();
|
||||||
|
// TODO: use actual font for corresponding DOM node to create text run.
|
||||||
let run = TextRun(&*ctx.font_cache.get_test_font(), text);
|
let run = TextRun(&*ctx.font_cache.get_test_font(), text);
|
||||||
let box_guts = TextBoxData(@run, 0, text.len());
|
let box_guts = TextBoxData(@run, 0, text.len());
|
||||||
dummy_boxes.set_elt(i, @TextBox(d, box_guts));
|
debug!("pushing when start=%?,end=%?", self.clump_start, self.clump_end);
|
||||||
|
temp_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
|
||||||
},
|
},
|
||||||
_ => {}
|
(false, true) => {
|
||||||
|
let mut run_str : ~str = ~"";
|
||||||
|
// TODO: is using ropes to construct the merged text any faster?
|
||||||
|
do uint::range(self.clump_start, self.clump_end+1) |i| {
|
||||||
|
run_str = str::append(run_str, in_boxes[i].raw_text()); true
|
||||||
|
}
|
||||||
|
// TODO: use actual font for corresponding DOM node to create text run.
|
||||||
|
let run = TextRun(&*ctx.font_cache.get_test_font(), move run_str);
|
||||||
|
let box_guts = TextBoxData(@run, 0, run.text.len());
|
||||||
|
debug!("pushing when start=%?,end=%?", self.clump_start, self.clump_end);
|
||||||
|
temp_boxes.push(@TextBox(copy *in_boxes[self.clump_start].d(), box_guts));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.in_clump = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,25 +191,30 @@ fn InlineFlowData() -> InlineFlowData {
|
||||||
trait InlineLayout {
|
trait InlineLayout {
|
||||||
pure fn starts_inline_flow() -> bool;
|
pure fn starts_inline_flow() -> bool;
|
||||||
|
|
||||||
fn bubble_widths_inline(ctx: &LayoutContext);
|
fn bubble_widths_inline(@self, ctx: &LayoutContext);
|
||||||
fn assign_widths_inline(ctx: &LayoutContext);
|
fn assign_widths_inline(@self, ctx: &LayoutContext);
|
||||||
fn assign_height_inline(ctx: &LayoutContext);
|
fn assign_height_inline(@self, ctx: &LayoutContext);
|
||||||
fn build_display_list_inline(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
fn build_display_list_inline(@self, a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowContext : InlineLayout {
|
impl FlowContext : InlineLayout {
|
||||||
pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }
|
pure fn starts_inline_flow() -> bool { match self { InlineFlow(*) => true, _ => false } }
|
||||||
|
|
||||||
fn bubble_widths_inline(ctx: &LayoutContext) {
|
fn bubble_widths_inline(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_inline_flow();
|
assert self.starts_inline_flow();
|
||||||
|
|
||||||
// TODO: this is a hack
|
debug!("box count: %u", self.inline().boxes.len());
|
||||||
build_runs_for_flow(ctx, &self.inline().boxes);
|
|
||||||
|
let scanner = TextRunScanner(self);
|
||||||
|
scanner.scan_for_runs(ctx);
|
||||||
|
|
||||||
let mut min_width = au(0);
|
let mut min_width = au(0);
|
||||||
let mut pref_width = au(0);
|
let mut pref_width = au(0);
|
||||||
|
|
||||||
|
debug!("/box count: %u", self.inline().boxes.len());
|
||||||
|
|
||||||
for self.inline().boxes.each |box| {
|
for self.inline().boxes.each |box| {
|
||||||
|
debug!("measuring box: %s", box.debug_str());
|
||||||
min_width = au::max(min_width, box.get_min_width(ctx));
|
min_width = au::max(min_width, box.get_min_width(ctx));
|
||||||
pref_width = au::max(pref_width, box.get_pref_width(ctx));
|
pref_width = au::max(pref_width, box.get_pref_width(ctx));
|
||||||
}
|
}
|
||||||
|
@ -111,7 +226,7 @@ impl FlowContext : InlineLayout {
|
||||||
/* Recursively (top-down) determines the actual width of child
|
/* Recursively (top-down) determines the actual width of child
|
||||||
contexts and boxes. When called on this context, the context has
|
contexts and boxes. When called on this context, the context has
|
||||||
had its width set by the parent context. */
|
had its width set by the parent context. */
|
||||||
fn assign_widths_inline(ctx: &LayoutContext) {
|
fn assign_widths_inline(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_inline_flow();
|
assert self.starts_inline_flow();
|
||||||
|
|
||||||
/* Perform inline flow with the available width. */
|
/* Perform inline flow with the available width. */
|
||||||
|
@ -170,12 +285,12 @@ impl FlowContext : InlineLayout {
|
||||||
// 'inline-block' box that created this flow.
|
// 'inline-block' box that created this flow.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height_inline(_ctx: &LayoutContext) {
|
fn assign_height_inline(@self, _ctx: &LayoutContext) {
|
||||||
// Don't need to set box or ctx heights, since that is done
|
// Don't need to set box or ctx heights, since that is done
|
||||||
// during inline flowing.
|
// during inline flowing.
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_inline(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
fn build_display_list_inline(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
|
|
||||||
assert self.starts_inline_flow();
|
assert self.starts_inline_flow();
|
||||||
|
|
|
@ -22,11 +22,12 @@ fn RootFlowData() -> RootFlowData {
|
||||||
trait RootLayout {
|
trait RootLayout {
|
||||||
pure fn starts_root_flow() -> bool;
|
pure fn starts_root_flow() -> bool;
|
||||||
|
|
||||||
fn bubble_widths_root(ctx: &LayoutContext);
|
fn bubble_widths_root(@self, ctx: &LayoutContext);
|
||||||
fn assign_widths_root(ctx: &LayoutContext);
|
fn assign_widths_root(@self, ctx: &LayoutContext);
|
||||||
fn assign_height_root(ctx: &LayoutContext);
|
fn assign_height_root(@self, ctx: &LayoutContext);
|
||||||
|
|
||||||
fn build_display_list_root(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
fn build_display_list_root(@self, a: &dl::DisplayListBuilder, b: &Rect<au>,
|
||||||
|
c: &Point2D<au>, d: &dl::DisplayList);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlowContext : RootLayout {
|
impl FlowContext : RootLayout {
|
||||||
|
@ -39,25 +40,25 @@ impl FlowContext : RootLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* defer to the block algorithm */
|
/* defer to the block algorithm */
|
||||||
fn bubble_widths_root(ctx: &LayoutContext) {
|
fn bubble_widths_root(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
self.bubble_widths_block(ctx)
|
self.bubble_widths_block(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_widths_root(ctx: &LayoutContext) {
|
fn assign_widths_root(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
|
|
||||||
self.d().position = copy ctx.screen_size;
|
self.d().position = copy ctx.screen_size;
|
||||||
self.assign_widths_block(ctx)
|
self.assign_widths_block(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assign_height_root(ctx: &LayoutContext) {
|
fn assign_height_root(@self, ctx: &LayoutContext) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
|
|
||||||
self.assign_height_block(ctx);
|
self.assign_height_block(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_display_list_root(builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
fn build_display_list_root(@self, builder: &dl::DisplayListBuilder, dirty: &Rect<au>,
|
||||||
offset: &Point2D<au>, list: &dl::DisplayList) {
|
offset: &Point2D<au>, list: &dl::DisplayList) {
|
||||||
assert self.starts_root_flow();
|
assert self.starts_root_flow();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use au::au;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use servo_text::text_run::TextRun;
|
use servo_text::text_run::TextRun;
|
||||||
use servo_text::font_cache::FontCache;
|
use servo_text::font_cache::FontCache;
|
||||||
use layout::box::{TextBox, RenderBox};
|
use layout::box::{TextBox, RenderBox, UnscannedTextBox};
|
||||||
use layout::context::LayoutContext;
|
use layout::context::LayoutContext;
|
||||||
|
|
||||||
pub struct TextBoxData {
|
pub struct TextBoxData {
|
||||||
|
@ -22,6 +22,19 @@ pub fn TextBoxData(run: @TextRun, offset: uint, length: uint) -> TextBoxData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait UnscannedMethods {
|
||||||
|
pure fn raw_text() -> ~str;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderBox : UnscannedMethods {
|
||||||
|
pure fn raw_text() -> ~str {
|
||||||
|
match self {
|
||||||
|
UnscannedTextBox(_, s) => copy s,
|
||||||
|
_ => fail ~"unsupported operation: box.raw_text() on non-unscanned text box."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The main reflow routine for text layout.
|
/* The main reflow routine for text layout.
|
||||||
impl @RenderBox : TextLayout {
|
impl @RenderBox : TextLayout {
|
||||||
fn reflow_text(ctx: &LayoutContext) {
|
fn reflow_text(ctx: &LayoutContext) {
|
||||||
|
|
|
@ -463,10 +463,10 @@ struct GlyphStore {
|
||||||
|
|
||||||
// Initializes the glyph store, but doesn't actually shape anything.
|
// Initializes the glyph store, but doesn't actually shape anything.
|
||||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||||
fn GlyphStore(text: &str) -> GlyphStore {
|
fn GlyphStore(length: uint) -> GlyphStore {
|
||||||
assert text.len() > 0;
|
assert length > 0;
|
||||||
|
|
||||||
let buffer = vec::from_elem(text.len(), InitialGlyphEntry());
|
let buffer = vec::from_elem(length, InitialGlyphEntry());
|
||||||
|
|
||||||
GlyphStore {
|
GlyphStore {
|
||||||
entry_buffer: dvec::from_vec(buffer),
|
entry_buffer: dvec::from_vec(buffer),
|
||||||
|
|
|
@ -26,16 +26,19 @@ impl TextRun {
|
||||||
assert offset < self.text.len();
|
assert offset < self.text.len();
|
||||||
assert offset + length <= self.text.len();
|
assert offset + length <= self.text.len();
|
||||||
|
|
||||||
|
debug!("enter min_width_for_range(o=%?, l=%?)", offset, length);
|
||||||
|
|
||||||
let mut max_piece_width = au(0);
|
let mut max_piece_width = au(0);
|
||||||
// TODO: use a real font reference
|
// TODO: use a real font reference
|
||||||
let font = ctx.font_cache.get_test_font();
|
let font = ctx.font_cache.get_test_font();
|
||||||
for self.iter_indivisible_pieces_for_range(offset, length) |piece_offset, piece_len| {
|
for self.iter_indivisible_pieces_for_range(offset, length) |piece_offset, piece_len| {
|
||||||
|
|
||||||
let metrics = font.measure_text(&self, piece_offset, piece_len);
|
let metrics = font.measure_text(&self, piece_offset, piece_len);
|
||||||
if metrics.advance > max_piece_width {
|
if metrics.advance > max_piece_width {
|
||||||
max_piece_width = metrics.advance;
|
max_piece_width = metrics.advance;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!("exit min_width_for_range(o=%?, l=%?)", offset, length);
|
||||||
return max_piece_width;
|
return max_piece_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +78,8 @@ impl TextRun {
|
||||||
assert offset < self.text.len();
|
assert offset < self.text.len();
|
||||||
assert offset + length <= self.text.len();
|
assert offset + length <= self.text.len();
|
||||||
|
|
||||||
|
debug!("enter iter_indivisible_pieces_for_range(o=%?, l=%?)", offset, length);
|
||||||
|
|
||||||
//TODO: need a more sophisticated model of words and possible breaks
|
//TODO: need a more sophisticated model of words and possible breaks
|
||||||
let text = str::view(self.text, offset, length);
|
let text = str::view(self.text, offset, length);
|
||||||
|
|
||||||
|
@ -117,11 +122,12 @@ impl TextRun {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
debug!("exit iter_indivisible_pieces_for_range(o=%?, l=%?)", offset, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn TextRun(font: &Font, +text: ~str) -> TextRun {
|
fn TextRun(font: &Font, text: ~str) -> TextRun {
|
||||||
let glyph_store = GlyphStore(text);
|
let glyph_store = GlyphStore(text.len());
|
||||||
let run = TextRun {
|
let run = TextRun {
|
||||||
text: text,
|
text: text,
|
||||||
glyphs: glyph_store,
|
glyphs: glyph_store,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue