diff --git a/src/components/gfx/text/shaping/harfbuzz.rs b/src/components/gfx/text/shaping/harfbuzz.rs index cf67452ccdc0..f4523630de61 100644 --- a/src/components/gfx/text/shaping/harfbuzz.rs +++ b/src/components/gfx/text/shaping/harfbuzz.rs @@ -64,17 +64,14 @@ pub struct ShapedGlyphEntry { impl ShapedGlyphData { pub fn new(buffer: *hb_buffer_t) -> ShapedGlyphData { unsafe { - let glyph_count = 0; + let glyph_count = 0 as c_uint; let glyph_infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); - let glyph_count = glyph_count as uint; assert!(glyph_infos.is_not_null()); - let pos_count = 0; - let pos_infos = hb_buffer_get_glyph_positions(buffer, &pos_count); + let pos_infos = hb_buffer_get_glyph_positions(buffer, &glyph_count); assert!(pos_infos.is_not_null()); - assert!(glyph_count == pos_count as uint); ShapedGlyphData { - count: glyph_count, + count: glyph_count as uint, glyph_infos: glyph_infos, pos_infos: pos_infos, } @@ -231,7 +228,11 @@ impl Shaper { // so, we must be careful to increment this when saving glyph entries. let mut char_idx = 0; - assert!(glyph_count <= char_max); + // FIXME(recrack) : glyph_count is depending on the font. + // Example : (I, II is roman upper character unicode) + // I = glyph_count(1u), char_max(1u) + // II = glyph_count(2u), char_max(1u) + //assert!(glyph_count <= char_max); debug!("Shaped text[char count={:u}], got back {:u} glyph info records.", char_max, diff --git a/src/components/main/css/user-agent.css b/src/components/main/css/user-agent.css index cc23479b21f7..3c799b2b43c5 100644 --- a/src/components/main/css/user-agent.css +++ b/src/components/main/css/user-agent.css @@ -51,22 +51,25 @@ thead, tbody, s, strike, del { text-decoration: line-through } hr { border: 1px inset } -/* lists */ -dd { display: block; margin-left: 40px } -p, dl, multicol { display: block; margin: 1em 0 } -ul { display: block; list-style-type: disc; - margin: 1em 0; padding-left: 40px } - -ol { display: block; list-style-type: decimal; - margin: 1em 0; padding-left: 40px } +p { display: block; margin: 1em 0 } +/* 14.3.8 Lists : http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#lists */ +dd, dl, dt, ol, ul { display: block; } li { display: list-item } +dl, ol, ul { margin-top: 1em; margin-bottom: 1em; } + /* nested lists have no top/bottom margins */ ul ul, ul ol, ul dl, ol ul, ol ol, ol dl, dl ul, dl ol, dl dl { margin-top: 0; margin-bottom: 0 } +dd { margin-left: 40px; } /* LTR-specific: use 'margin-right' for rtl elements */ +ol, ul { padding-left: 40px; } /* LTR-specific: use 'padding-right' for rtl elements */ + +ol { list-style-type: decimal; } +ul { list-style-type: disc; } + /* 2 deep unordered lists use a circle */ ol ul, ul ul { list-style-type: circle; } @@ -75,14 +78,14 @@ ol ol ul, ol ul ul, ul ol ul, ul ul ul { list-style-type: square; } /* The type attribute on ol and ul elements */ -ul[type="disc"] { list-style-type: disc; } -ul[type="circle"] { list-style-type: circle; } -ul[type="square"] { list-style-type: square; } -ol[type="1"] { list-style-type: decimal; } -ol[type="a"] { list-style-type: lower-alpha; } -ol[type="A"] { list-style-type: upper-alpha; } -ol[type="i"] { list-style-type: lower-roman; } -ol[type="I"] { list-style-type: upper-roman; } +ol[type="1"], li[type="1"] { list-style-type: decimal; } +ol[type="a"], li[type="a"] { list-style-type: lower-alpha; } +ol[type="A"], li[type="A"] { list-style-type: upper-alpha; } +ol[type="i"], li[type="i"] { list-style-type: lower-roman; } +ol[type="I"], li[type="I"] { list-style-type: upper-roman; } +ul[type="disc"], li[type="disc"] { list-style-type: disc; } +ul[type="circle"], li[type="circle"] { list-style-type: circle; } +ul[type="square"], li[type="square"] { list-style-type: square; } u, ins { text-decoration: underline } br:before { content: "\A"; white-space: pre-line } diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs index e3388a223701..bc8effe4bff7 100644 --- a/src/components/main/layout/block.rs +++ b/src/components/main/layout/block.rs @@ -120,6 +120,10 @@ impl BlockFlow { self.float.is_some() } + pub fn is_list(&self) -> bool { + self.base.listdata.is_some() + } + pub fn teardown(&mut self) { for box_ in self.box_.iter() { box_.teardown(); @@ -492,16 +496,32 @@ impl BlockFlow { box_.position.set(position); } + /// wrapper of build_display_list. For switching to html list. + pub fn build_display_list_wrapper( + &self, + builder: &DisplayListBuilder, + dirty: &Rect, + offset: Point2D, + flow: &Flow, + list: &RefCell>) { + if self.is_list() { + for box_ in self.box_.iter() { + box_.add_marker_to_display_list(builder, dirty, flow, list) + } + } + + // add box that starts block context + for box_ in self.box_.iter() { + box_.build_display_list(builder, dirty, offset, flow, list) + } + } + pub fn build_display_list_block( &mut self, builder: &DisplayListBuilder, dirty: &Rect, list: &RefCell>) -> bool { - if self.is_float() { - return self.build_display_list_float(builder, dirty, list); - } - let abs_rect = Rect(self.base.abs_position, self.base.position.size); if !abs_rect.intersects(dirty) { return true; @@ -509,10 +529,8 @@ impl BlockFlow { debug!("build_display_list_block: adding display element"); - // add box that starts block context - for box_ in self.box_.iter() { - box_.build_display_list(builder, dirty, self.base.abs_position, (&*self) as &Flow, list) - } + self.build_display_list_wrapper(builder, dirty, self.base.abs_position, (&*self) as &Flow, list); + // TODO: handle any out-of-flow elements let this_position = self.base.abs_position; @@ -536,11 +554,8 @@ impl BlockFlow { } let offset = self.base.abs_position + self.float.get_ref().rel_pos; - // add box that starts block context - for box_ in self.box_.iter() { - box_.build_display_list(builder, dirty, offset, (&*self) as &Flow, list) - } - + + self.build_display_list_wrapper(builder, dirty, offset, (&*self) as &Flow, list); // TODO: handle any out-of-flow elements diff --git a/src/components/main/layout/box_.rs b/src/components/main/layout/box_.rs index 1403fc9d39b1..a905f2cea6b3 100644 --- a/src/components/main/layout/box_.rs +++ b/src/components/main/layout/box_.rs @@ -14,6 +14,7 @@ use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, TextD use gfx::display_list::{TextDisplayItemClass, TextDisplayItemFlags, ClipDisplayItem}; use gfx::display_list::{ClipDisplayItemClass}; use gfx::font::FontStyle; +use gfx::font_context::FontContext; use gfx::text::text_run::TextRun; use servo_msg::constellation_msg::{FrameRectMsg, PipelineId, SubpageId}; @@ -1210,6 +1211,62 @@ impl Box { self.paint_borders_if_applicable(list, &absolute_box_bounds); } + /// Adds list marker into displaylist. This refers listdata in FlowData. + /// FIXME(aydin.kim) : Is it better that we add ListBox and handle in build_display_list? + pub fn add_marker_to_display_list( + &self, + builder: &DisplayListBuilder, + dirty: &Rect, + flow: &Flow, + list: &RefCell>) { + if self.style().Box.visibility != visibility::visible { + return; + } + + let listdata = flow::base(flow).listdata.unwrap(); + let convert = builder.numbers; + let text = convert.to_list_style_type(listdata.list_style_type, listdata.sequence); + + let color = self.style().Color.color.to_gfx_color(); + let font_style = self.font_style(); + //FIXME(aydin.kim) : In the future, we do not have to create new font context. Need to get unicode chracter values from css style sheet directly. when we will complete that works, this code has to be modified. + let mut font_context = ~FontContext::new(builder.ctx.font_context_info.clone()); + let fontgroup = font_context.get_resolved_font_for_style(&font_style); + let text = RefCell::new(text); + let run = ~fontgroup.borrow().with(|fg| fg.create_textrun(text.get(), text_decoration::none)); + let text_range = Range::new(0, text.get().len()); + let text_bounds = run.metrics_for_range(&text_range).bounding_box; + let em_size = text_bounds.size.height; + let line_height = self.calculate_line_height(em_size); + let text_offset = (line_height - em_size).scale_by(0.5); + let marker_offset = &Point2D(-run.min_width_for_range(&text_range), text_offset); + + let marker_bound = Rect(flow::base(flow).abs_position, text_bounds.size).translate(marker_offset); + if !marker_bound.intersects(dirty) { + return; + } + + + // Create the text box. + list.with_mut(|list| { + let text_display_item = ~TextDisplayItem { + base: BaseDisplayItem { + bounds: marker_bound, + extra: ExtraDisplayListData::new(self), + }, + text_run: Arc::new(run.clone()), + range: text_range, + text_color: color, + overline_color: color, + underline_color: color, + line_through_color: color, + flags: TextDisplayItemFlags::new(), + }; + + list.append_item(TextDisplayItemClass(text_display_item)) + }); + + } /// Returns the *minimum width* and *preferred width* of this box as defined by CSS 2.1. pub fn minimum_and_preferred_widths(&self) -> (Au, Au) { let guessed_width = self.guess_width(); diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs index e2605e6bd6ca..17967ede0831 100644 --- a/src/components/main/layout/construct.rs +++ b/src/components/main/layout/construct.rs @@ -27,20 +27,25 @@ use layout::box_::{UnscannedTextBox, UnscannedTextBoxInfo, InlineInfo, InlinePar use layout::context::LayoutContext; use layout::float_context::FloatType; use layout::flow::{BaseFlow, Flow, LeafSet, MutableOwnedFlowUtils}; +use layout::flow; use layout::inline::InlineFlow; use layout::text::TextRunScanner; use layout::util::{LayoutDataAccess, OpaqueNode}; -use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal}; +use layout::wrapper::{LayoutNode, PostorderNodeMutTraversal, LayoutElement}; use gfx::font_context::FontContext; use script::dom::element::{HTMLIframeElementTypeId, HTMLImageElementTypeId}; +use script::dom::element::{HTMLUListElementTypeId, HTMLOListElementTypeId, ElementTypeId}; use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, TextNodeTypeId}; use style::computed_values::{display, position, float}; +use style::TNode; +use style::TElement; use std::cell::RefCell; use std::util; use std::num::Zero; +use servo_util::namespace; /// The results of flow construction for a DOM node. pub enum ConstructionResult { @@ -295,6 +300,57 @@ impl<'fc> FlowConstructor<'fc> { } } + fn recursive_order_check(&mut self, flow: &mut ~Flow, mut list_cnt: int, is_ordered: bool, is_reversed: bool) -> int { + for child_flow in flow::child_iter(*flow) { + list_cnt = self.recursive_order_check(child_flow, list_cnt, is_ordered, is_reversed); + match child_flow.class() { + flow::BlockFlowClass => { + if child_flow.as_block().is_list() && !child_flow.as_block().base.listdata.get_mut_ref().sequenced() { + child_flow.as_block().base.listdata.get_mut_ref().from_list_tag(list_cnt, is_ordered); + if is_reversed { list_cnt -= 1; } + else { list_cnt += 1; } + } + }, + _ => {}, + } + } + list_cnt + } + + fn parse_attr_for_list(&mut self, node: LayoutNode) -> (Option, int, bool, bool) { + //FIXME(aydin.kim) : boost up the flow traverse. Sequence checking in time of parsing is needed? + let mut list_start_num: int = 1; + let mut is_ordered = false; + let mut is_reversed = false; + return match node.type_id() { + ElementNodeTypeId(typeid) if typeid == HTMLUListElementTypeId || typeid == HTMLOListElementTypeId=> { + match typeid { + HTMLUListElementTypeId => { + is_ordered = false; + }, + HTMLOListElementTypeId => { + is_ordered = true; + + match node.with_element(|e: &LayoutElement| {e.get_attr(&namespace::Null, "start")}) { + Some(s) => { + let conv_seq: Option = from_str(s); + if conv_seq.is_some() { list_start_num = conv_seq.unwrap(); } + else { list_start_num = 1; } + }, + None => {}, + }; + if node.with_element(|e: &LayoutElement| {e.get_attr(&namespace::Null, "reversed")}).is_some() { + is_reversed = true; + } + }, + _ => {}, + } + (Some(typeid), list_start_num, is_ordered, is_reversed) + }, + _ =>(None, 1, false, false) //just a dummy value + } + } + /// Builds the children flows underneath a node with `display: block`. After this call, /// other `BlockFlow`s or `InlineFlow`s will be populated underneath this node, depending on /// whether {ib} splits needed to happen. @@ -304,10 +360,15 @@ impl<'fc> FlowConstructor<'fc> { // Gather up boxes for the inline flows we might need to create. let mut opt_boxes_for_inline_flow = None; let mut first_box = true; + + let (list_type, list_start_num, is_ordered, is_reversed) = self.parse_attr_for_list(node); + let mut list_cnt = list_start_num; + + // Children.. for kid in node.children() { match kid.swap_out_construction_result() { NoConstructionResult => {} - FlowConstructionResult(kid_flow) => { + FlowConstructionResult(mut kid_flow) => { // Strip ignorable whitespace from the start of this flow per CSS 2.1 § // 9.2.1.1. if first_box { @@ -315,6 +376,21 @@ impl<'fc> FlowConstructor<'fc> { first_box = false } + //Processing html list tag for backward compatibility. + if list_type.is_some() { + if kid_flow.as_block().is_list() && !kid_flow.as_block().base.listdata.get_mut_ref().sequenced() { + kid_flow.as_block().base.listdata.get_mut_ref().from_list_tag(list_cnt, is_ordered); + if is_reversed { list_cnt -= 1; } + else { list_cnt += 1; } + } + + if (kid.type_id() != ElementNodeTypeId(HTMLUListElementTypeId)) + && (kid.type_id() != ElementNodeTypeId(HTMLOListElementTypeId)) { + //FIXME(aydin.kim): Actually we don't need sequence and reverse check in the case of UL. + list_cnt = self.recursive_order_check(&mut kid_flow, list_cnt, is_ordered, is_reversed); + } + } + // Flush any inline boxes that we were gathering up. This allows us to handle // {ib} splits. debug!("flushing {} inline box(es) to flow A", @@ -388,6 +464,18 @@ impl<'fc> FlowConstructor<'fc> { node); } + ///Builds a flow for a node. In here, we can switch the flow type to make. + fn build_block_flow(&mut self, node: LayoutNode, float_value: float::T, is_fixed: bool) -> ~Flow { + let flow = match float_value { + float::none => self.build_flow_for_block(node, is_fixed), + _ => { + let float_type = FloatType::from_property(float_value); + self.build_flow_for_floated_block(node, float_type) + } + }; + flow + } + /// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed /// to happen. @@ -651,15 +739,10 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { let flow = self.build_flow_for_block(node, true); node.set_flow_construction_result(FlowConstructionResult(flow)) } - (_, float::none, _) => { - let flow = self.build_flow_for_block(node, false); - node.set_flow_construction_result(FlowConstructionResult(flow)) - } // Floated flows contribute float flow construction results. (_, float_value, _) => { - let float_type = FloatType::from_property(float_value); - let flow = self.build_flow_for_floated_block(node, float_type); + let flow = self.build_block_flow(node, float_value, false); node.set_flow_construction_result(FlowConstructionResult(flow)) } } diff --git a/src/components/main/layout/counter_style.rs b/src/components/main/layout/counter_style.rs new file mode 100644 index 000000000000..6e915f764ef5 --- /dev/null +++ b/src/components/main/layout/counter_style.rs @@ -0,0 +1,189 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Number converter, +// This file will be move from main/layout to style/ + +use std::hashmap::HashMap; + +use style::computed_values::list_style_type; + +pub trait Roman { + fn to_roman(&self, number: int) -> ~str; +} + +impl Roman for HashMap { + fn to_roman(&self, number: int) -> ~str { + let base = ~[1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]; + let mut num = number; + let mut result = ~""; + for &i in base.iter() { + while num >= i { + match self.find(&i) { + None => fail!("key is not matched."), + Some(v) => { + num -= i; + result.push_str(*v); + } + } + } + } + return result; + } +} + +struct RomanNumber { + upper_romans: HashMap, + lower_romans: HashMap +} + +impl RomanNumber { + fn new() -> RomanNumber { + RomanNumber { + upper_romans: init_upper_roman(), + lower_romans: init_lower_roman() + } + } + + fn to_upper(&self, number: int) -> ~str { + self.upper_romans.to_roman(number) + } + + fn to_lower(&self, number: int) -> ~str { + self.lower_romans.to_roman(number) + } +} + +fn init_upper_roman() -> HashMap { + let mut map: HashMap = HashMap::new();//with_capacity(20); + map.insert(1, ~"\u2160"); + map.insert(2, ~"\u2161"); + map.insert(3, ~"\u2162"); + map.insert(4, ~"\u2163"); + map.insert(5, ~"\u2164"); + map.insert(6, ~"\u2165"); + map.insert(7, ~"\u2166"); + map.insert(8, ~"\u2167"); + map.insert(9, ~"\u2168"); + map.insert(10, ~"\u2169"); + //map.insert(11, ~"\u216A"); // http://www.fileformat.info/info/unicode/char/216A/index.htm + //map.insert(12, ~"\u216B"); // http://www.fileformat.info/info/unicode/char/216B/index.htm + map.insert(40, ~"\u2169\u216C"); + map.insert(50, ~"\u216C"); // http://www.fileformat.info/info/unicode/char/216C/index.htm + map.insert(90, ~"\u2169\u216D"); + map.insert(100, ~"\u216D"); // Unicode Character 'ROMAN NUMERAL ONE HUNDRED' (U+216D) + map.insert(400, ~"\u216C\u216E"); + map.insert(500, ~"\u216E"); // Unicode Character 'ROMAN NUMERAL FIVE HUNDRED' (U+216E) + map.insert(900, ~"\u216D\u216F"); + map.insert(1000, ~"\u216F"); //Unicode Character 'ROMAN NUMERAL ONE THOUSAND' (U+216F) + + return map; +} + +fn init_lower_roman() -> HashMap { + let mut map: HashMap = HashMap::new();//with_capacity(20); + map.insert(1, ~"\u2170"); // Unicode Character 'SMALL ROMAN NUMERAL ONE' (U+2170) + map.insert(2, ~"\u2171"); + map.insert(3, ~"\u2172"); + map.insert(4, ~"\u2173"); + map.insert(5, ~"\u2174"); + map.insert(6, ~"\u2175"); + map.insert(7, ~"\u2176"); + map.insert(8, ~"\u2177"); + map.insert(9, ~"\u2178"); + map.insert(10, ~"\u2179"); + //map.insert(11, ~"\u217A"); // Unicode Character 'SMALL ROMAN NUMERAL ELEVEN' (U+217A) + //map.insert(12, ~"\u217B"); // Unicode Character 'SMALL ROMAN NUMERAL TWELVE' (U+217B) + map.insert(40, ~"\u2179\u217C"); + map.insert(50, ~"\u217C"); // http://www.fileformat.info/info/unicode/char/217C/index.htm + map.insert(90, ~"\u2179\u217D"); + map.insert(100, ~"\u217D"); // Unicode Character 'SMALL ROMAN NUMERAL ONE HUNDRED' (U+217D) + map.insert(400, ~"\u217C\u217E"); + map.insert(500, ~"\u217E"); // Unicode Character 'SMALL ROMAN NUMERAL FIVE HUNDRED' (U+217E) + map.insert(900, ~"\u217D\u217F"); + map.insert(1000, ~"\u217F"); //Unicode Character 'SMALL ROMAN NUMERAL ONE THOUSAND' (U+217F) + + return map; +} + +pub struct Numbers { + roman: RomanNumber, +} + +impl Numbers { + pub fn new() -> Numbers { + Numbers { roman: RomanNumber::new() } + } + + /// generate list_style_type. + pub fn to_list_style_type(&self, style_type: list_style_type::T, sequence: int) -> ~str { + + // if sequence is minus or zero + if sequence <= 0 { + return sequence.to_str() + self.dot_space(); + } + + match style_type { + + //Ordered + //list_style_type::decimal_leading_zero => self.to_decimal_leading_zero(sequence) + self.dot_space(), + list_style_type::decimal => { sequence.to_str() + self.dot_space() }, + list_style_type::lower_roman => self.to_lower_roman(sequence) + self.dot_space(), + list_style_type::upper_roman => self.to_upper_roman(sequence) + self.dot_space(), + //list_style_type::lower_greek => self.to_lower_greek(sequence) + self.dot_space(), + //list_style_type::lower_latin => self.to_lower_latin(sequence) + self.dot_space(), + //list_style_type::upper_latin => self.to_upper_latin(sequence) + self.dot_space(), + //list_style_type::lower_alpha => self.to_lower_alpha(sequence) + self.dot_space(), + //list_style_type::upper_alpha => self.to_upper_alpha(sequence) + self.dot_space(), + //list_style_type::armenian => self.to_armenian(sequence) + self.dot_space(), + //list_style_type::georgian => self.to_georgian(sequence) + self.dot_space(), + + //UnOrdered + list_style_type::circle => ~"\u25CB" + self.space(), // ○ + list_style_type::disc => ~"\u25CF" + self.space(), // ● + list_style_type::square => ~"\u25A0" + self.space(), // ■ + + list_style_type::none => ~"", // type is none + } + } + pub fn dot_space(&self) -> ~str { + ~"\u002E" + self.space() + } + pub fn space(&self) -> ~str { + ~"\u2009" + } + pub fn to_decimal_leading_zero(&self, _number: int) -> ~str { + fail!("TODO: decimal_leading_zero"); + } + pub fn to_upper_roman(&self, number: int) -> ~str { + self.roman.to_upper(number) + } + pub fn to_lower_roman(&self, number: int) -> ~str { + self.roman.to_lower(number) + } + pub fn to_upper_alpha(&self, _number: int) -> ~str { + fail!("TODO: upper-alpha"); + } + pub fn to_lower_alpha(&self, _number: int) -> ~str { + fail!("TODO: lower-alpha"); + } + pub fn to_upper_latin(&self, _number: int) -> ~str { + fail!("TODO: upper-latin"); + } + pub fn to_lower_latin(&self, _number: int) -> ~str { + fail!("TODO: lower-latin"); + } + pub fn to_upper_greek(&self, _number: int) -> ~str { + fail!("there is no upper-greek property"); + } + pub fn to_lower_greek(&self, _number: int) -> ~str { + fail!("TODO: lower-greek"); + } + pub fn to_armenian(&self, _number: int) -> ~str { + fail!("TODO: armenian"); + } + pub fn to_georgian(&self, _number: int) -> ~str { + fail!("TODO: georgian"); + } +} diff --git a/src/components/main/layout/display_list_builder.rs b/src/components/main/layout/display_list_builder.rs index dc20f784667e..c5d33b6f72f4 100644 --- a/src/components/main/layout/display_list_builder.rs +++ b/src/components/main/layout/display_list_builder.rs @@ -7,6 +7,7 @@ use layout::box_::Box; use layout::context::LayoutContext; use layout::util::OpaqueNode; +use layout::counter_style; use gfx; use style; @@ -37,6 +38,7 @@ impl ExtraDisplayListData for Nothing { /// support display-list-based hit testing and so forth. pub struct DisplayListBuilder<'a> { ctx: &'a LayoutContext, + numbers: &'a counter_style::Numbers, } // @@ -54,4 +56,3 @@ impl ToGfxColor for style::computed_values::RGBA { gfx::color::rgba(self.red, self.green, self.blue, self.alpha) } } - diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs index 175baeddea64..6b885445bf7a 100644 --- a/src/components/main/layout/flow.rs +++ b/src/components/main/layout/flow.rs @@ -51,6 +51,8 @@ use std::hashmap::{HashSet, HashSetIterator}; use std::sync::atomics::Relaxed; use style::ComputedValues; use style::computed_values::text_align; +use style::computed_values::display; +use style::computed_values::{list_style_position, list_style_type, list_style_image}; /// Virtual methods that make up a float context. /// @@ -473,6 +475,62 @@ impl FlowFlags { } } +/// FIXME(aydin.kim): We have to change list_style_type to be in the form of bitfield if it is possible to reduce resources. +pub struct ListData { + list_style_type: list_style_type::T, + list_style_position: list_style_position::T, + list_style_image: list_style_image::T, + + //we need set_done flag because we don'know the flow kind. we cannot check this is checked or not in previous step. + seq_set_done : bool, + is_ordered : bool, + sequence : int, +} + +impl ListData { + #[inline] + pub fn new(style: &ComputedValues) -> Option { + if style.Box.display == display::list_item { + let mut data = ListData { + //This css values have higher priority than html type attr below. + list_style_type : list_style_type::disc, + list_style_position : list_style_position::outside, + list_style_image : list_style_image::none, + + seq_set_done: false, + is_ordered: false, + sequence : 1, + }; + + data.set_override_list_type(style); + data.set_override_list_position(style); + data.set_override_list_image(style); + + Some(data) + } + else { + None + } + } + pub fn set_override_list_type(&mut self, style: &ComputedValues) { + self.list_style_type = style.List.list_style_type; + } + pub fn set_override_list_position(&mut self, style: &ComputedValues) { + self.list_style_position = style.List.list_style_position; + } + pub fn set_override_list_image(&mut self, style: &ComputedValues) { + self.list_style_image = style.List.list_style_image; + } + pub fn from_list_tag(&mut self, value: int, is_ordered: bool) { + self.is_ordered = is_ordered; + self.sequence = value; + self.seq_set_done = true; + } + pub fn sequenced(&mut self) -> bool { + self.seq_set_done + } +} + /// Data common to all flows. pub struct BaseFlow { restyle_damage: RestyleDamage, @@ -515,6 +573,7 @@ pub struct BaseFlow { /// Various flags for flows and some info flags_info: FlowFlagsInfo, + listdata: Option, } impl Drop for BaseFlow { @@ -568,6 +627,7 @@ impl BaseFlow { destroyed: false, flags_info: FlowFlagsInfo::new(style.get()), + listdata: ListData::new(style.get()), } } @@ -706,8 +766,15 @@ impl<'a> MutableFlowUtils for &'a mut Flow { list: &RefCell>) -> bool { debug!("Flow: building display list for f{}", base(self).id); + match self.class() { - BlockFlowClass => self.as_block().build_display_list_block(builder, dirty, list), + BlockFlowClass => { + if self.as_block().float.is_some() { + self.as_block().build_display_list_float(builder, dirty, list) + } else { + self.as_block().build_display_list_block(builder, dirty, list) + } + } InlineFlowClass => self.as_inline().build_display_list_inline(builder, dirty, list), }; @@ -717,7 +784,7 @@ impl<'a> MutableFlowUtils for &'a mut Flow { let child_list = ~RefCell::new(DisplayList::new()); for kid in child_iter(self) { - kid.build_display_list(builder,dirty,child_list); + kid.build_display_list(builder, dirty, child_list); } let mut child_list = Some(child_list.unwrap()); diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs index 01bae0b94289..eddef0119c0d 100644 --- a/src/components/main/layout/layout_task.rs +++ b/src/components/main/layout/layout_task.rs @@ -21,6 +21,7 @@ use layout::parallel::{UnsafeFlow}; use layout::parallel; use layout::util::{LayoutDataAccess, OpaqueNode, LayoutDataWrapper}; use layout::wrapper::LayoutNode; +use layout::counter_style; use extra::arc::{Arc, MutexArc, RWArc}; use geom::rect::Rect; @@ -563,6 +564,7 @@ impl LayoutTask { let dirty = flow::base(layout_root).position.clone(); let display_list_builder = DisplayListBuilder { ctx: &layout_ctx, + numbers: &counter_style::Numbers::new(), }; layout_root.build_display_list(&display_list_builder, &dirty, display_list); diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc old mode 100755 new mode 100644 index 342aacae57f2..40a8f559866e --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -97,6 +97,7 @@ pub mod layout { pub mod model; pub mod parallel; pub mod text; + pub mod counter_style; pub mod util; pub mod incremental; pub mod wrapper; diff --git a/src/components/style/properties.rs.mako b/src/components/style/properties.rs.mako index 602a0a695c4f..a299ebaabcae 100644 --- a/src/components/style/properties.rs.mako +++ b/src/components/style/properties.rs.mako @@ -433,6 +433,41 @@ pub mod longhands { Some(Content(content)) } + + // 12.5 Lists + ${new_style_struct("List")} + ${single_keyword("list-style-type", "disc circle square decimal lower-roman upper-roman none", inherited=True)} // TODO: decimal-leading-zero lower-greek lower-latin upper-latin armenian georgian lower-alpha upper-alpha + ${single_keyword("list-style-image", "none", inherited=True)} // TODO: url(image.jpg) + + // TODO: outside inside + <%self:single_component_value name="list-style-position" inherited="True"> + // The computed value is the same as the specified value. + pub use to_computed_value = super::computed_as_specified; + + pub mod computed_value { + #[deriving(Eq, Clone, FromPrimitive)] + pub enum T { + outside, + inside, + } + } + pub type SpecifiedValue = computed_value::T; + #[inline] pub fn get_initial_value() -> computed_value::T { + outside + } + pub fn from_component_value(v: &ComponentValue) -> Option { + get_ident_lower(v).and_then(|keyword| { + match keyword.as_slice() { + _ => { + println!("Unsupported property: {:?}", keyword.as_slice()); + None + } + } + }) + } + + + // CSS 2.1, Section 13 - Paged media // CSS 2.1, Section 14 - Colors and Backgrounds @@ -766,6 +801,77 @@ pub mod shorthands { + // 12 - Generated content, automatic numbering, and lists + + // 12.5 Lists + <%self:shorthand name="list-style" sub_properties="list-style-type list-style-position + list-style-image"> + let mut none_count = 0u; + let mut property_count = 0u; + let mut iter = input.skip_whitespace(); + let mut style_type = None; + let mut style_position = None; + let mut style_image = None; + for component_value in iter { + property_count += 1; + + // list-style-type and list-style-image has none propertiy. + if get_ident_lower(component_value).filtered( + |v| v.eq_ignore_ascii_case("none")).is_some() { + none_count += 1; + continue; + } + + // list-style-type parsing check + match list_style_type::from_component_value(component_value) { + Some(v) => { + if style_type.is_some() { return None; } + style_type = Some(v); + continue + }, + None => (), + } + + // list-style-position parsing check + match list_style_position::from_component_value(component_value) { + Some(v) => { + if style_position.is_some() { return None; } + style_position = Some(v); + continue + }, + None => () + } + + // list-style-position parsing check + match list_style_image::from_component_value(component_value) { + Some(v) => { + if style_image.is_some() { return None; } + style_image = Some(v); + continue + }, + None => () + } + + // if component value is wrong, return None. + return None; + } + + // list-style could have three properties. + // if list-style have more than 3, it will return None. + if property_count > 3 { return None } + + if style_type.is_none() && none_count > 0 { style_type = Some(list_style_type::none); none_count -= 1; } + if style_image.is_none() && none_count > 0 { style_image = Some(list_style_image::none); none_count -= 1; } + + // If too many none, return None. + if none_count > 0 { return None; } + + Some(Longhands { + list_style_type: style_type, + list_style_position: style_position, + list_style_image: style_image + }) + // TODO: other background-* properties <%self:shorthand name="background" sub_properties="background-color">