mirror of
https://github.com/servo/servo.git
synced 2025-08-09 15:35:34 +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 with_block_box(fn(box: &@RenderBox) -> ()) -> ();
|
||||
|
||||
fn bubble_widths_block(ctx: &LayoutContext);
|
||||
fn assign_widths_block(ctx: &LayoutContext);
|
||||
fn assign_height_block(ctx: &LayoutContext);
|
||||
fn bubble_widths_block(@self, ctx: &LayoutContext);
|
||||
fn assign_widths_block(@self, 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);
|
||||
}
|
||||
|
||||
|
@ -66,14 +66,14 @@ impl FlowContext : BlockLayout {
|
|||
/* TODO: floats */
|
||||
/* TODO: absolute contexts */
|
||||
/* TODO: inline-blocks */
|
||||
fn bubble_widths_block(ctx: &LayoutContext) {
|
||||
fn bubble_widths_block(@self, ctx: &LayoutContext) {
|
||||
assert self.starts_block_flow();
|
||||
|
||||
let mut min_width = au(0);
|
||||
let mut pref_width = au(0);
|
||||
|
||||
/* 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();
|
||||
|
||||
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
|
||||
all child (block) contexts. */
|
||||
|
||||
fn assign_widths_block(_ctx: &LayoutContext) {
|
||||
fn assign_widths_block(@self, _ctx: &LayoutContext) {
|
||||
assert self.starts_block_flow();
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
child_ctx.d().position.origin.x = left_used;
|
||||
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();
|
||||
|
||||
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;
|
||||
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) {
|
||||
|
||||
assert self.starts_block_flow();
|
||||
|
@ -155,7 +155,7 @@ impl FlowContext : BlockLayout {
|
|||
// TODO: handle any out-of-flow elements
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ struct RenderBoxData {
|
|||
enum RenderBoxType {
|
||||
RenderBox_Generic,
|
||||
RenderBox_Image,
|
||||
RenderBox_Text
|
||||
RenderBox_Text,
|
||||
}
|
||||
|
||||
pub enum RenderBox {
|
||||
|
@ -101,6 +101,8 @@ trait RenderBoxMethods {
|
|||
pure fn d(&self) -> &self/RenderBoxData;
|
||||
|
||||
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 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
|
||||
* may cause glyphs to be allocated. For now, it's impure because of
|
||||
* holder.get_image()
|
||||
|
|
|
@ -32,19 +32,19 @@ pub struct DisplayListBuilder {
|
|||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
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>,
|
||||
list: &dl::DisplayList) {
|
||||
|
||||
|
|
|
@ -130,39 +130,39 @@ fn FlowData(id: int) -> FlowData {
|
|||
|
||||
/* Flow context disambiguation methods: the verbose alternative to virtual methods */
|
||||
impl FlowContext {
|
||||
fn bubble_widths(ctx: &LayoutContext) {
|
||||
fn bubble_widths(@self, ctx: &LayoutContext) {
|
||||
match self {
|
||||
BlockFlow(*) => self.bubble_widths_block(ctx),
|
||||
InlineFlow(*) => self.bubble_widths_inline(ctx),
|
||||
RootFlow(*) => self.bubble_widths_root(ctx),
|
||||
@BlockFlow(*) => self.bubble_widths_block(ctx),
|
||||
@InlineFlow(*) => self.bubble_widths_inline(ctx),
|
||||
@RootFlow(*) => self.bubble_widths_root(ctx),
|
||||
_ => fail fmt!("Tried to bubble_widths of flow: %?", self)
|
||||
}
|
||||
}
|
||||
|
||||
fn assign_widths(ctx: &LayoutContext) {
|
||||
fn assign_widths(@self, ctx: &LayoutContext) {
|
||||
match self {
|
||||
BlockFlow(*) => self.assign_widths_block(ctx),
|
||||
InlineFlow(*) => self.assign_widths_inline(ctx),
|
||||
RootFlow(*) => self.assign_widths_root(ctx),
|
||||
@BlockFlow(*) => self.assign_widths_block(ctx),
|
||||
@InlineFlow(*) => self.assign_widths_inline(ctx),
|
||||
@RootFlow(*) => self.assign_widths_root(ctx),
|
||||
_ => fail fmt!("Tried to assign_widths of flow: %?", self)
|
||||
}
|
||||
}
|
||||
|
||||
fn assign_height(ctx: &LayoutContext) {
|
||||
fn assign_height(@self, ctx: &LayoutContext) {
|
||||
match self {
|
||||
BlockFlow(*) => self.assign_height_block(ctx),
|
||||
InlineFlow(*) => self.assign_height_inline(ctx),
|
||||
RootFlow(*) => self.assign_height_root(ctx),
|
||||
@BlockFlow(*) => self.assign_height_block(ctx),
|
||||
@InlineFlow(*) => self.assign_height_inline(ctx),
|
||||
@RootFlow(*) => self.assign_height_root(ctx),
|
||||
_ => 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) {
|
||||
match self {
|
||||
RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
||||
BlockFlow(*) => self.build_display_list_block(builder, dirty, offset, list),
|
||||
InlineFlow(*) => self.build_display_list_inline(builder, dirty, offset, list),
|
||||
@RootFlow(*) => self.build_display_list_root(builder, dirty, offset, list),
|
||||
@BlockFlow(*) => self.build_display_list_block(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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,6 @@ use std::arc;
|
|||
use util::tree;
|
||||
|
||||
/*
|
||||
Tentative design: (may not line up with reality)
|
||||
|
||||
Lineboxes are represented as offsets into the child list, rather than
|
||||
as an object that "owns" boxes. Choosing a different set of line
|
||||
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};
|
||||
|
||||
// TODO: flesh out into TextRunScanner
|
||||
fn build_runs_for_flow(ctx: &LayoutContext, dummy_boxes: &DVec<@RenderBox>) {
|
||||
for uint::range(0, dummy_boxes.len()) |i| {
|
||||
match *dummy_boxes[i] {
|
||||
UnscannedTextBox(d, text) => {
|
||||
// stack-allocated object for scanning an inline flow into
|
||||
// TextRun-containing TextBoxes.
|
||||
struct TextRunScanner {
|
||||
mut in_clump: bool,
|
||||
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 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 {
|
||||
pure fn starts_inline_flow() -> bool;
|
||||
|
||||
fn bubble_widths_inline(ctx: &LayoutContext);
|
||||
fn assign_widths_inline(ctx: &LayoutContext);
|
||||
fn assign_height_inline(ctx: &LayoutContext);
|
||||
fn build_display_list_inline(a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
||||
fn bubble_widths_inline(@self, ctx: &LayoutContext);
|
||||
fn assign_widths_inline(@self, ctx: &LayoutContext);
|
||||
fn assign_height_inline(@self, ctx: &LayoutContext);
|
||||
fn build_display_list_inline(@self, a: &dl::DisplayListBuilder, b: &Rect<au>, c: &Point2D<au>, d: &dl::DisplayList);
|
||||
}
|
||||
|
||||
impl FlowContext : InlineLayout {
|
||||
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();
|
||||
|
||||
// TODO: this is a hack
|
||||
build_runs_for_flow(ctx, &self.inline().boxes);
|
||||
debug!("box count: %u", self.inline().boxes.len());
|
||||
|
||||
let scanner = TextRunScanner(self);
|
||||
scanner.scan_for_runs(ctx);
|
||||
|
||||
let mut min_width = au(0);
|
||||
let mut pref_width = au(0);
|
||||
|
||||
debug!("/box count: %u", self.inline().boxes.len());
|
||||
|
||||
for self.inline().boxes.each |box| {
|
||||
debug!("measuring box: %s", box.debug_str());
|
||||
min_width = au::max(min_width, box.get_min_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
|
||||
contexts and boxes. When called on this context, the context has
|
||||
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();
|
||||
|
||||
/* Perform inline flow with the available width. */
|
||||
|
@ -170,12 +285,12 @@ impl FlowContext : InlineLayout {
|
|||
// '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
|
||||
// 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) {
|
||||
|
||||
assert self.starts_inline_flow();
|
||||
|
|
|
@ -22,11 +22,12 @@ fn RootFlowData() -> RootFlowData {
|
|||
trait RootLayout {
|
||||
pure fn starts_root_flow() -> bool;
|
||||
|
||||
fn bubble_widths_root(ctx: &LayoutContext);
|
||||
fn assign_widths_root(ctx: &LayoutContext);
|
||||
fn assign_height_root(ctx: &LayoutContext);
|
||||
fn bubble_widths_root(@self, ctx: &LayoutContext);
|
||||
fn assign_widths_root(@self, 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 {
|
||||
|
@ -39,25 +40,25 @@ impl FlowContext : RootLayout {
|
|||
}
|
||||
|
||||
/* defer to the block algorithm */
|
||||
fn bubble_widths_root(ctx: &LayoutContext) {
|
||||
fn bubble_widths_root(@self, ctx: &LayoutContext) {
|
||||
assert self.starts_root_flow();
|
||||
self.bubble_widths_block(ctx)
|
||||
}
|
||||
|
||||
fn assign_widths_root(ctx: &LayoutContext) {
|
||||
fn assign_widths_root(@self, ctx: &LayoutContext) {
|
||||
assert self.starts_root_flow();
|
||||
|
||||
self.d().position = copy ctx.screen_size;
|
||||
self.assign_widths_block(ctx)
|
||||
}
|
||||
|
||||
fn assign_height_root(ctx: &LayoutContext) {
|
||||
fn assign_height_root(@self, ctx: &LayoutContext) {
|
||||
assert self.starts_root_flow();
|
||||
|
||||
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) {
|
||||
assert self.starts_root_flow();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use au::au;
|
|||
use geom::size::Size2D;
|
||||
use servo_text::text_run::TextRun;
|
||||
use servo_text::font_cache::FontCache;
|
||||
use layout::box::{TextBox, RenderBox};
|
||||
use layout::box::{TextBox, RenderBox, UnscannedTextBox};
|
||||
use layout::context::LayoutContext;
|
||||
|
||||
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.
|
||||
impl @RenderBox : TextLayout {
|
||||
fn reflow_text(ctx: &LayoutContext) {
|
||||
|
|
|
@ -463,10 +463,10 @@ struct GlyphStore {
|
|||
|
||||
// Initializes the glyph store, but doesn't actually shape anything.
|
||||
// Use the set_glyph, set_glyphs() methods to store glyph data.
|
||||
fn GlyphStore(text: &str) -> GlyphStore {
|
||||
assert text.len() > 0;
|
||||
fn GlyphStore(length: uint) -> GlyphStore {
|
||||
assert length > 0;
|
||||
|
||||
let buffer = vec::from_elem(text.len(), InitialGlyphEntry());
|
||||
let buffer = vec::from_elem(length, InitialGlyphEntry());
|
||||
|
||||
GlyphStore {
|
||||
entry_buffer: dvec::from_vec(buffer),
|
||||
|
|
|
@ -26,16 +26,19 @@ impl TextRun {
|
|||
assert offset < 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);
|
||||
// TODO: use a real font reference
|
||||
let font = ctx.font_cache.get_test_font();
|
||||
for self.iter_indivisible_pieces_for_range(offset, length) |piece_offset, piece_len| {
|
||||
|
||||
let metrics = font.measure_text(&self, piece_offset, piece_len);
|
||||
if metrics.advance > max_piece_width {
|
||||
max_piece_width = metrics.advance;
|
||||
}
|
||||
};
|
||||
|
||||
debug!("exit min_width_for_range(o=%?, l=%?)", offset, length);
|
||||
return max_piece_width;
|
||||
}
|
||||
|
||||
|
@ -75,6 +78,8 @@ impl TextRun {
|
|||
assert offset < 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
|
||||
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 {
|
||||
let glyph_store = GlyphStore(text);
|
||||
fn TextRun(font: &Font, text: ~str) -> TextRun {
|
||||
let glyph_store = GlyphStore(text.len());
|
||||
let run = TextRun {
|
||||
text: text,
|
||||
glyphs: glyph_store,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue