diff --git a/components/canvas/canvas_paint_task.rs b/components/canvas/canvas_paint_task.rs index 2f0c36fd40eb..f2e8323d6a26 100644 --- a/components/canvas/canvas_paint_task.rs +++ b/components/canvas/canvas_paint_task.rs @@ -9,13 +9,15 @@ use geom::size::Size2D; use servo_util::task::spawn_named; use std::comm; +use std::sync::Arc; -#[deriving(Copy)] +#[deriving(Clone)] pub enum CanvasMsg { FillRect(Rect), ClearRect(Rect), StrokeRect(Rect), Recreate(Size2D), + SendPixelContents(Sender>>), Close, } @@ -29,7 +31,7 @@ pub struct CanvasPaintTask { impl CanvasPaintTask { fn new(size: Size2D) -> CanvasPaintTask { CanvasPaintTask { - drawtarget: CanvasPaintTask::create(size), + drawtarget: CanvasPaintTask::create_with_data(size), fill_color: ColorPattern::new(Color::new(0., 0., 0., 1.)), stroke_color: ColorPattern::new(Color::new(0., 0., 0., 1.)), stroke_opts: StrokeOptions::new(1.0, 1.0), @@ -47,6 +49,7 @@ impl CanvasPaintTask { CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect), CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect), CanvasMsg::Recreate(size) => painter.recreate(size), + CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan), CanvasMsg::Close => break, } } @@ -68,11 +71,20 @@ impl CanvasPaintTask { self.drawtarget.stroke_rect(rect, &self.stroke_color, &self.stroke_opts, &drawopts); } - fn create(size: Size2D) -> DrawTarget { - DrawTarget::new(BackendType::Skia, size, SurfaceFormat::B8G8R8A8) + fn create_with_data(size: Size2D) -> DrawTarget { + DrawTarget::new_with_data(BackendType::Skia, + Vec::from_elem((size.width * size.height * 4) as uint, 0u8), + 0, + size, + size.width * 4, + SurfaceFormat::B8G8R8A8) } fn recreate(&mut self, size: Size2D) { - self.drawtarget = CanvasPaintTask::create(size); + self.drawtarget = CanvasPaintTask::create_with_data(size); + } + + fn send_pixel_contents(&mut self, chan: Sender>>) { + chan.send(self.drawtarget.data.clone().unwrap()); } } diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 7db6466d48b9..eb90fbf734e3 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -24,6 +24,7 @@ use flow; use flow_ref::FlowRef; use fragment::{Fragment, IframeFragmentInfo}; use fragment::ImageFragmentInfo; +use fragment::CanvasFragmentInfo; use fragment::InlineAbsoluteHypotheticalFragmentInfo; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo}; use fragment::TableColumnFragmentInfo; @@ -272,6 +273,9 @@ impl<'a> FlowConstructor<'a> { Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement))) | Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement))) => SpecificFragmentInfo::TableRow, Some(NodeTypeId::Text) => SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)), + Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => { + SpecificFragmentInfo::Canvas(box CanvasFragmentInfo::new(node)) + } _ => { // This includes pseudo-elements. SpecificFragmentInfo::Generic @@ -1145,7 +1149,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { } }; - debug!("building flow for node: {} {}", display, float); + debug!("building flow for node: {} {} {}", display, float, node.type_id()); // Switch on display and floatedness. match (display, float, positioning) { @@ -1288,6 +1292,7 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> { None | Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => true, Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLObjectElement))) => self.has_object_data(), + Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => true, Some(NodeTypeId::Element(_)) => false, } } diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 75279b2b7db1..c394edb4a51f 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -11,6 +11,7 @@ #![deny(unsafe_blocks)] use block::BlockFlow; +use canvas::canvas_paint_task::CanvasMsg::SendPixelContents; use context::LayoutContext; use flow::{mod, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER}; use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo}; @@ -32,12 +33,14 @@ use gfx::display_list::TextOrientation; use gfx::display_list::{SolidColorDisplayItem}; use gfx::display_list::{StackingContext, TextDisplayItem}; use gfx::paint_task::PaintLayer; +use png; +use png::PixelsByColorType; use servo_msg::compositor_msg::ScrollPolicy; use servo_msg::constellation_msg::Msg as ConstellationMsg; use servo_msg::constellation_msg::ConstellationChan; use servo_net::image::holder::ImageHolder; use servo_util::cursor::Cursor; -use servo_util::geometry::{mod, Au}; +use servo_util::geometry::{mod, Au, to_px}; use servo_util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize}; use servo_util::opts; use std::default::Default; @@ -862,6 +865,37 @@ impl FragmentDisplayListBuilding for Fragment { debug!("(building display list) no image :("); } } + SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { + let width = canvas_fragment_info.replaced_image_fragment_info + .computed_inline_size.map_or(0, |w| to_px(w) as uint); + let height = canvas_fragment_info.replaced_image_fragment_info + .computed_block_size.map_or(0, |h| to_px(h) as uint); + + let (sender, receiver) = channel::>>(); + let canvas_data = match canvas_fragment_info.renderer { + Some(ref renderer) => { + renderer.deref().lock().send(SendPixelContents(sender)); + (*receiver.recv()).clone() + }, + None => Vec::from_elem(width * height * 4, 0xFFu8) + }; + + let canvas_display_item = box ImageDisplayItem { + base: BaseDisplayItem::new(stacking_relative_content_box, + DisplayItemMetadata::new(self.node, + &*self.style, + Cursor::DefaultCursor), + (*clip).clone()), + image: Arc::new(box png::Image { + width: width as u32, + height: height as u32, + pixels: PixelsByColorType::RGBA8(canvas_data), + }), + stretch_size: stacking_relative_content_box.size, + }; + + display_list.content.push_back(DisplayItem::ImageClass(canvas_display_item)); + } } } diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index a0a3a99ac65b..6217527bf6ba 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -6,6 +6,7 @@ #![deny(unsafe_blocks)] +use canvas::canvas_paint_task::CanvasMsg; use css::node_style::StyledNode; use construct::FlowConstructor; use context::LayoutContext; @@ -128,6 +129,7 @@ pub enum SpecificFragmentInfo { Generic, Iframe(Box), Image(Box), + Canvas(Box), /// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was /// declared with `display: inline;`. @@ -156,6 +158,7 @@ impl SpecificFragmentInfo { | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::UnscannedText(_) + | SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Generic => return RestyleDamage::empty(), SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref, SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref, @@ -166,6 +169,7 @@ impl SpecificFragmentInfo { pub fn get_type(&self) -> &'static str { match *self { + SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas", SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic", SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe", SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image", @@ -217,17 +221,40 @@ impl InlineBlockFragmentInfo { } } +#[deriving(Clone)] +pub struct CanvasFragmentInfo { + pub replaced_image_fragment_info: ReplacedImageFragmentInfo, + pub renderer: Option>>>, +} + +impl CanvasFragmentInfo { + pub fn new(node: &ThreadSafeLayoutNode) -> CanvasFragmentInfo { + CanvasFragmentInfo { + replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, + Some(Au::from_px(node.get_canvas_width() as int)), + Some(Au::from_px(node.get_canvas_height() as int))), + renderer: node.get_renderer().map(|rec| Arc::new(Mutex::new(rec))), + } + } + + /// Returns the original inline-size of the canvas. + pub fn canvas_inline_size(&self) -> Au { + self.replaced_image_fragment_info.dom_inline_size.unwrap_or(Au(0)) + } + + /// Returns the original block-size of the canvas. + pub fn canvas_block_size(&self) -> Au { + self.replaced_image_fragment_info.dom_block_size.unwrap_or(Au(0)) + } +} + + /// A fragment that represents a replaced content image and its accompanying borders, shadows, etc. #[deriving(Clone)] pub struct ImageFragmentInfo { /// The image held within this fragment. + pub replaced_image_fragment_info: ReplacedImageFragmentInfo, pub image: ImageHolder, - pub for_node: UntrustedNodeAddress, - pub computed_inline_size: Option, - pub computed_block_size: Option, - pub dom_inline_size: Option, - pub dom_block_size: Option, - pub writing_mode_is_vertical: bool, } impl ImageFragmentInfo { @@ -247,15 +274,60 @@ impl ImageFragmentInfo { }).and_then(|pixels| Some(Au::from_px(pixels))) } - let is_vertical = node.style().writing_mode.is_vertical(); - let dom_width = convert_length(node, &atom!("width")); - let dom_height = convert_length(node, &atom!("height")); + ImageFragmentInfo { + replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, + convert_length(node, &atom!("width")), + convert_length(node, &atom!("height"))), + image: ImageHolder::new(image_url, local_image_cache) + } + } + + /// Returns the original inline-size of the image. + pub fn image_inline_size(&mut self) -> Au { + let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero()); + Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { size.height } + else { size.width }) + } + + /// Returns the original block-size of the image. + pub fn image_block_size(&mut self) -> Au { + let size = self.image.get_size(self.replaced_image_fragment_info.for_node).unwrap_or(Size2D::zero()); + Au::from_px(if self.replaced_image_fragment_info.writing_mode_is_vertical { size.width } + else { size.height }) + } + + /// Tile an image + pub fn tile_image(position: &mut Au, size: &mut Au, + virtual_position: Au, image_size: u32) { + let image_size = image_size as int; + let delta_pixels = geometry::to_px(virtual_position - *position); + let tile_count = (delta_pixels + image_size - 1) / image_size; + let offset = Au::from_px(image_size * tile_count); + let new_position = virtual_position - offset; + *size = *position - new_position + *size; + *position = new_position; + } +} + +#[deriving(Clone)] +pub struct ReplacedImageFragmentInfo { + pub for_node: UntrustedNodeAddress, + pub computed_inline_size: Option, + pub computed_block_size: Option, + pub dom_inline_size: Option, + pub dom_block_size: Option, + pub writing_mode_is_vertical: bool, +} +impl ReplacedImageFragmentInfo { + pub fn new(node: &ThreadSafeLayoutNode, + dom_width: Option, + dom_height: Option) -> ReplacedImageFragmentInfo { + let is_vertical = node.style().writing_mode.is_vertical(); let opaque_node: OpaqueNode = OpaqueNodeMethods::from_thread_safe_layout_node(node); let untrusted_node: UntrustedNodeAddress = opaque_node.to_untrusted_node_address(); - ImageFragmentInfo { - image: ImageHolder::new(image_url, local_image_cache), + ReplacedImageFragmentInfo { for_node: untrusted_node, computed_inline_size: None, computed_block_size: None, @@ -275,18 +347,6 @@ impl ImageFragmentInfo { self.computed_block_size.expect("image block_size is not computed yet!") } - /// Returns the original inline-size of the image. - pub fn image_inline_size(&mut self) -> Au { - let size = self.image.get_size(self.for_node).unwrap_or(Size2D::zero()); - Au::from_px(if self.writing_mode_is_vertical { size.height } else { size.width }) - } - - /// Returns the original block-size of the image. - pub fn image_block_size(&mut self) -> Au { - let size = self.image.get_size(self.for_node).unwrap_or(Size2D::zero()); - Au::from_px(if self.writing_mode_is_vertical { size.width } else { size.height }) - } - // Return used value for inline-size or block-size. // // `dom_length`: inline-size or block-size as specified in the `img` tag. @@ -319,16 +379,101 @@ impl ImageFragmentInfo { }) } - /// Tile an image - pub fn tile_image(position: &mut Au, size: &mut Au, - virtual_position: Au, image_size: u32) { - let image_size = image_size as int; - let delta_pixels = geometry::to_px(virtual_position - *position); - let tile_count = (delta_pixels + image_size - 1) / image_size; - let offset = Au::from_px(image_size * tile_count); - let new_position = virtual_position - offset; - *size = *position - new_position + *size; - *position = new_position; + pub fn calculate_replaced_inline_size(&mut self, + style: ComputedValues, + noncontent_inline_size: Au, + container_inline_size: Au, + fragment_inline_size: Au, + fragment_block_size: Au) -> Au { + + let style_inline_size = style.content_inline_size(); + let style_block_size = style.content_block_size(); + let style_min_inline_size = style.min_inline_size(); + let style_max_inline_size = style.max_inline_size(); + let style_min_block_size = style.min_block_size(); + let style_max_block_size = style.max_block_size(); + + // TODO(ksh8281): compute border,margin + let inline_size = ReplacedImageFragmentInfo::style_length( + style_inline_size, + self.dom_inline_size, + container_inline_size); + + let inline_size = match inline_size { + MaybeAuto::Auto => { + let intrinsic_width = fragment_inline_size; + let intrinsic_height = fragment_block_size; + if intrinsic_height == Au(0) { + intrinsic_width + } else { + let ratio = intrinsic_width.to_f32().unwrap() / + intrinsic_height.to_f32().unwrap(); + + let specified_height = ReplacedImageFragmentInfo::style_length( + style_block_size, + self.dom_block_size, + Au(0)); + let specified_height = match specified_height { + MaybeAuto::Auto => intrinsic_height, + MaybeAuto::Specified(h) => h, + }; + let specified_height = ReplacedImageFragmentInfo::clamp_size( + specified_height, + style_min_block_size, + style_max_block_size, + Au(0)); + Au((specified_height.to_f32().unwrap() * ratio) as i32) + } + }, + MaybeAuto::Specified(w) => w, + }; + + let inline_size = ReplacedImageFragmentInfo::clamp_size(inline_size, + style_min_inline_size, + style_max_inline_size, + container_inline_size); + + self.computed_inline_size = Some(inline_size); + inline_size + noncontent_inline_size + } + + pub fn calculate_replaced_block_size(&mut self, + style: ComputedValues, + noncontent_block_size: Au, + containing_block_block_size: Au, + fragment_inline_size: Au, + fragment_block_size: Au) -> Au { + + // TODO(ksh8281): compute border,margin,padding + let style_block_size = style.content_block_size(); + let style_min_block_size = style.min_block_size(); + let style_max_block_size = style.max_block_size(); + + let inline_size = self.computed_inline_size(); + let block_size = ReplacedImageFragmentInfo::style_length( + style_block_size, + self.dom_block_size, + containing_block_block_size); + + let block_size = match block_size { + MaybeAuto::Auto => { + let intrinsic_width = fragment_inline_size; + let intrinsic_height = fragment_block_size; + let scale = intrinsic_width.to_f32().unwrap() / inline_size.to_f32().unwrap(); + Au((intrinsic_height.to_f32().unwrap() / scale) as i32) + }, + MaybeAuto::Specified(h) => { + h + } + }; + + let block_size = ReplacedImageFragmentInfo::clamp_size(block_size, + style_min_block_size, + style_max_block_size, + Au(0)); + + self.computed_block_size = Some(block_size); + block_size + noncontent_block_size } } @@ -667,6 +812,7 @@ impl Fragment { fn quantities_included_in_intrinsic_inline_size(&self) -> QuantitiesIncludedInIntrinsicInlineSizes { match self.specific { + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | @@ -1000,6 +1146,13 @@ impl Fragment { preferred_inline_size: image_inline_size, }) } + SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => { + let canvas_inline_size = canvas_fragment_info.canvas_inline_size(); + result.union_block(&IntrinsicISizes { + minimum_inline_size: canvas_inline_size, + preferred_inline_size: canvas_inline_size, + }) + } SpecificFragmentInfo::ScannedText(ref text_fragment_info) => { let range = &text_fragment_info.range; let min_line_inline_size = text_fragment_info.run.min_width_for_range(range); @@ -1046,8 +1199,11 @@ impl Fragment { SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0), + SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { + canvas_fragment_info.replaced_image_fragment_info.computed_inline_size() + } SpecificFragmentInfo::Image(ref image_fragment_info) => { - image_fragment_info.computed_inline_size() + image_fragment_info.replaced_image_fragment_info.computed_inline_size() } SpecificFragmentInfo::ScannedText(ref text_fragment_info) => { let (range, run) = (&text_fragment_info.range, &text_fragment_info.run); @@ -1066,7 +1222,10 @@ impl Fragment { SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0), SpecificFragmentInfo::Image(ref image_fragment_info) => { - image_fragment_info.computed_block_size() + image_fragment_info.replaced_image_fragment_info.computed_block_size() + } + SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { + canvas_fragment_info.replaced_image_fragment_info.computed_block_size() } SpecificFragmentInfo::ScannedText(_) => { // Compute the block-size based on the line-block-size and font size. @@ -1097,7 +1256,7 @@ impl Fragment { pub fn find_split_info_by_new_line(&self) -> Option<(SplitInfo, Option, Arc> /* TODO(bjz): remove */)> { match self.specific { - SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => None, SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not need to split"), SpecificFragmentInfo::UnscannedText(_) => panic!("Unscanned text fragments should have been scanned by now!"), @@ -1300,7 +1459,7 @@ impl Fragment { /// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced /// content per CSS 2.1 § 10.3.2. - pub fn assign_replaced_inline_size_if_necessary(&mut self, container_inline_size: Au) { + pub fn assign_replaced_inline_size_if_necessary<'a>(&'a mut self, container_inline_size: Au) { match self.specific { SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return, @@ -1308,16 +1467,11 @@ impl Fragment { SpecificFragmentInfo::UnscannedText(_) => { panic!("Unscanned text fragments should have been scanned by now!") } - SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {} }; - let style_inline_size = self.style().content_inline_size(); - let style_block_size = self.style().content_block_size(); - let style_min_inline_size = self.style().min_inline_size(); - let style_max_inline_size = self.style().max_inline_size(); - let style_min_block_size = self.style().min_block_size(); - let style_max_block_size = self.style().max_block_size(); + let style = self.style().clone(); let noncontent_inline_size = self.border_padding.inline_start_end(); match self.specific { @@ -1341,49 +1495,24 @@ impl Fragment { self.border_box.size.inline = info.content_size.inline + noncontent_inline_size } SpecificFragmentInfo::Image(ref mut image_fragment_info) => { - // TODO(ksh8281): compute border,margin - let inline_size = ImageFragmentInfo::style_length( - style_inline_size, - image_fragment_info.dom_inline_size, - container_inline_size); - - let inline_size = match inline_size { - MaybeAuto::Auto => { - let intrinsic_width = image_fragment_info.image_inline_size(); - let intrinsic_height = image_fragment_info.image_block_size(); - - if intrinsic_height == Au(0) { - intrinsic_width - } else { - let ratio = intrinsic_width.to_f32().unwrap() / - intrinsic_height.to_f32().unwrap(); - - let specified_height = ImageFragmentInfo::style_length( - style_block_size, - image_fragment_info.dom_block_size, - Au(0)); - let specified_height = match specified_height { - MaybeAuto::Auto => intrinsic_height, - MaybeAuto::Specified(h) => h, - }; - let specified_height = ImageFragmentInfo::clamp_size( - specified_height, - style_min_block_size, - style_max_block_size, - Au(0)); - Au((specified_height.to_f32().unwrap() * ratio) as i32) - } - }, - MaybeAuto::Specified(w) => w, - }; - - let inline_size = ImageFragmentInfo::clamp_size(inline_size, - style_min_inline_size, - style_max_inline_size, - container_inline_size); - - self.border_box.size.inline = inline_size + noncontent_inline_size; - image_fragment_info.computed_inline_size = Some(inline_size); + let fragment_inline_size = image_fragment_info.image_inline_size(); + let fragment_block_size = image_fragment_info.image_block_size(); + self.border_box.size.inline = image_fragment_info.replaced_image_fragment_info. + calculate_replaced_inline_size(style, + noncontent_inline_size, + container_inline_size, + fragment_inline_size, + fragment_block_size); + } + SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => { + let fragment_inline_size = canvas_fragment_info.canvas_inline_size(); + let fragment_block_size = canvas_fragment_info.canvas_block_size(); + self.border_box.size.inline = canvas_fragment_info.replaced_image_fragment_info. + calculate_replaced_inline_size(style, + noncontent_inline_size, + container_inline_size, + fragment_inline_size, + fragment_block_size); } _ => panic!("this case should have been handled above"), } @@ -1401,42 +1530,33 @@ impl Fragment { SpecificFragmentInfo::UnscannedText(_) => { panic!("Unscanned text fragments should have been scanned by now!") } - SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::ScannedText(_) | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {} } - let style_block_size = self.style().content_block_size(); - let style_min_block_size = self.style().min_block_size(); - let style_max_block_size = self.style().max_block_size(); + let style = self.style().clone(); let noncontent_block_size = self.border_padding.block_start_end(); match self.specific { SpecificFragmentInfo::Image(ref mut image_fragment_info) => { - // TODO(ksh8281): compute border,margin,padding - let inline_size = image_fragment_info.computed_inline_size(); - let block_size = ImageFragmentInfo::style_length( - style_block_size, - image_fragment_info.dom_block_size, - containing_block_block_size); - - let block_size = match block_size { - MaybeAuto::Auto => { - let scale = image_fragment_info.image_inline_size().to_f32().unwrap() - / inline_size.to_f32().unwrap(); - Au((image_fragment_info.image_block_size().to_f32().unwrap() / scale) - as i32) - }, - MaybeAuto::Specified(h) => { - h - } - }; - - let block_size = ImageFragmentInfo::clamp_size(block_size, style_min_block_size, - style_max_block_size, - Au(0)); - - image_fragment_info.computed_block_size = Some(block_size); - self.border_box.size.block = block_size + noncontent_block_size + let fragment_inline_size = image_fragment_info.image_inline_size(); + let fragment_block_size = image_fragment_info.image_block_size(); + self.border_box.size.block = image_fragment_info.replaced_image_fragment_info. + calculate_replaced_block_size(style, + noncontent_block_size, + containing_block_block_size, + fragment_inline_size, + fragment_block_size); + } + SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => { + let fragment_inline_size = canvas_fragment_info.canvas_inline_size(); + let fragment_block_size = canvas_fragment_info.canvas_block_size(); + self.border_box.size.block = canvas_fragment_info.replaced_image_fragment_info. + calculate_replaced_block_size(style, + noncontent_block_size, + containing_block_block_size, + fragment_inline_size, + fragment_block_size); } SpecificFragmentInfo::ScannedText(ref info) => { // Scanned text fragments' content block-sizes are calculated by the text run @@ -1463,7 +1583,7 @@ impl Fragment { pub fn inline_metrics(&self, layout_context: &LayoutContext) -> InlineMetrics { match self.specific { SpecificFragmentInfo::Image(ref image_fragment_info) => { - let computed_block_size = image_fragment_info.computed_block_size(); + let computed_block_size = image_fragment_info.replaced_image_fragment_info.computed_block_size(); InlineMetrics { block_size_above_baseline: computed_block_size + self.border_padding.block_start_end(), depth_below_baseline: Au(0), @@ -1538,6 +1658,7 @@ impl Fragment { SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::TableWrapper => false, + SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | diff --git a/components/layout/lib.rs b/components/layout/lib.rs index c71ba4696046..5fc89dbd82d9 100644 --- a/components/layout/lib.rs +++ b/components/layout/lib.rs @@ -13,12 +13,14 @@ extern crate log; extern crate cssparser; +extern crate canvas; extern crate geom; extern crate gfx; extern crate layout_traits; extern crate script; extern crate script_traits; extern crate serialize; +extern crate png; extern crate style; #[phase(plugin)] extern crate "plugins" as servo_plugins; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index c22bb367b60b..e11587710fa5 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -30,6 +30,7 @@ //! o Instead of `html_element_in_html_document()`, use //! `html_element_in_html_document_for_layout()`. +use canvas::canvas_paint_task::CanvasMsg; use context::SharedLayoutContext; use css::node_style::StyledNode; use incremental::RestyleDamage; @@ -39,12 +40,13 @@ use util::{PrivateLayoutData}; use cssparser::RGBA; use gfx::display_list::OpaqueNode; use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast}; -use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementCast, HTMLInputElementCast}; +use script::dom::bindings::codegen::InheritTypes::{HTMLCanvasElementCast, HTMLImageElementCast, HTMLInputElementCast}; use script::dom::bindings::codegen::InheritTypes::{HTMLTextAreaElementCast, NodeCast, TextCast}; use script::dom::bindings::js::JS; use script::dom::element::{Element, ElementTypeId}; use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::htmlelement::HTMLElementTypeId; +use script::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers}; use script::dom::htmliframeelement::HTMLIFrameElement; use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers; use script::dom::htmlinputelement::LayoutHTMLInputElementHelpers; @@ -112,6 +114,27 @@ pub trait TLayoutNode { } } + fn get_renderer(&self) -> Option> { + unsafe { + let canvas_element: Option> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); + canvas_element.and_then(|elem| elem.get_renderer()) + } + } + + fn get_canvas_width(&self) -> u32 { + unsafe { + let canvas_element: Option> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); + canvas_element.unwrap().get_canvas_width() + } + } + + fn get_canvas_height(&self) -> u32 { + unsafe { + let canvas_element: Option> = HTMLCanvasElementCast::to_js(self.get_jsmanaged()); + canvas_element.unwrap().get_canvas_height() + } + } + /// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is /// not an iframe element, fails. fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) { diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs index 71a4b639cf26..9ed36217fec1 100644 --- a/components/script/dom/canvasrenderingcontext2d.rs +++ b/components/script/dom/canvasrenderingcontext2d.rs @@ -44,6 +44,16 @@ impl CanvasRenderingContext2D { } } +pub trait LayoutCanvasRenderingContext2DHelpers { + unsafe fn get_renderer(&self) -> Sender; +} + +impl LayoutCanvasRenderingContext2DHelpers for JS { + unsafe fn get_renderer(&self) -> Sender { + (*self.unsafe_get()).renderer.clone() + } +} + impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> { fn Canvas(self) -> Temporary { Temporary::new(self.canvas) diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index eb02b6bc87d4..15f25a495a5c 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -2,6 +2,7 @@ * 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/. */ +use canvas::canvas_paint_task::CanvasMsg; use dom::attr::Attr; use dom::attr::AttrHelpers; use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding; @@ -9,8 +10,8 @@ use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElemen use dom::bindings::codegen::InheritTypes::HTMLCanvasElementDerived; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{MutNullableJS, JSRef, Temporary}; -use dom::canvasrenderingcontext2d::CanvasRenderingContext2D; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary}; +use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers}; use dom::document::Document; use dom::element::{Element, AttributeHandlers}; use dom::eventtarget::{EventTarget, EventTargetTypeId}; @@ -60,6 +61,27 @@ impl HTMLCanvasElement { } } +pub trait LayoutHTMLCanvasElementHelpers { + unsafe fn get_renderer(&self) -> Option>; + unsafe fn get_canvas_width(&self) -> u32; + unsafe fn get_canvas_height(&self) -> u32; +} + +impl LayoutHTMLCanvasElementHelpers for JS { + unsafe fn get_renderer(&self) -> Option> { + let context = (*self.unsafe_get()).context.get_inner(); + context.map(|cx| cx.get_renderer()) + } + + unsafe fn get_canvas_width(&self) -> u32 { + (*self.unsafe_get()).width.get() + } + + unsafe fn get_canvas_height(&self) -> u32 { + (*self.unsafe_get()).height.get() + } +} + impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> { fn Width(self) -> u32 { self.width.get() diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index d3303893e1a0..8fbb6ac44f12 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -26,7 +26,7 @@ dependencies = [ [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" +source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 79a672ab4c70..71b2c193052f 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -27,7 +27,7 @@ dependencies = [ [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" +source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index f6021634e706..783221c02b33 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "azure" version = "0.1.0" -source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" +source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898" dependencies = [ "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",