CanvasRenderTask connected to Layout

Update rust-azure to f4a02f3f621b0a994a20d42e438371a87c62f898.
This commit is contained in:
Edit Balint 2014-11-27 18:25:47 +01:00
parent 43e34d6d10
commit 81f47344d6
11 changed files with 359 additions and 130 deletions

View file

@ -9,13 +9,15 @@ use geom::size::Size2D;
use servo_util::task::spawn_named; use servo_util::task::spawn_named;
use std::comm; use std::comm;
use std::sync::Arc;
#[deriving(Copy)] #[deriving(Clone)]
pub enum CanvasMsg { pub enum CanvasMsg {
FillRect(Rect<f32>), FillRect(Rect<f32>),
ClearRect(Rect<f32>), ClearRect(Rect<f32>),
StrokeRect(Rect<f32>), StrokeRect(Rect<f32>),
Recreate(Size2D<i32>), Recreate(Size2D<i32>),
SendPixelContents(Sender<Arc<Vec<u8>>>),
Close, Close,
} }
@ -29,7 +31,7 @@ pub struct CanvasPaintTask {
impl CanvasPaintTask { impl CanvasPaintTask {
fn new(size: Size2D<i32>) -> CanvasPaintTask { fn new(size: Size2D<i32>) -> CanvasPaintTask {
CanvasPaintTask { CanvasPaintTask {
drawtarget: CanvasPaintTask::create(size), drawtarget: CanvasPaintTask::create_with_data(size),
fill_color: ColorPattern::new(Color::new(0., 0., 0., 1.)), fill_color: ColorPattern::new(Color::new(0., 0., 0., 1.)),
stroke_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), stroke_opts: StrokeOptions::new(1.0, 1.0),
@ -47,6 +49,7 @@ impl CanvasPaintTask {
CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect), CanvasMsg::StrokeRect(ref rect) => painter.stroke_rect(rect),
CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect), CanvasMsg::ClearRect(ref rect) => painter.clear_rect(rect),
CanvasMsg::Recreate(size) => painter.recreate(size), CanvasMsg::Recreate(size) => painter.recreate(size),
CanvasMsg::SendPixelContents(chan) => painter.send_pixel_contents(chan),
CanvasMsg::Close => break, CanvasMsg::Close => break,
} }
} }
@ -68,11 +71,20 @@ impl CanvasPaintTask {
self.drawtarget.stroke_rect(rect, &self.stroke_color, &self.stroke_opts, &drawopts); self.drawtarget.stroke_rect(rect, &self.stroke_color, &self.stroke_opts, &drawopts);
} }
fn create(size: Size2D<i32>) -> DrawTarget { fn create_with_data(size: Size2D<i32>) -> DrawTarget {
DrawTarget::new(BackendType::Skia, size, SurfaceFormat::B8G8R8A8) 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<i32>) { fn recreate(&mut self, size: Size2D<i32>) {
self.drawtarget = CanvasPaintTask::create(size); self.drawtarget = CanvasPaintTask::create_with_data(size);
}
fn send_pixel_contents(&mut self, chan: Sender<Arc<Vec<u8>>>) {
chan.send(self.drawtarget.data.clone().unwrap());
} }
} }

View file

@ -24,6 +24,7 @@ use flow;
use flow_ref::FlowRef; use flow_ref::FlowRef;
use fragment::{Fragment, IframeFragmentInfo}; use fragment::{Fragment, IframeFragmentInfo};
use fragment::ImageFragmentInfo; use fragment::ImageFragmentInfo;
use fragment::CanvasFragmentInfo;
use fragment::InlineAbsoluteHypotheticalFragmentInfo; use fragment::InlineAbsoluteHypotheticalFragmentInfo;
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo}; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
use fragment::TableColumnFragmentInfo; use fragment::TableColumnFragmentInfo;
@ -272,6 +273,9 @@ impl<'a> FlowConstructor<'a> {
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement))) | Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableRowElement))) |
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement))) => SpecificFragmentInfo::TableRow, Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLTableSectionElement))) => SpecificFragmentInfo::TableRow,
Some(NodeTypeId::Text) => SpecificFragmentInfo::UnscannedText(UnscannedTextFragmentInfo::new(node)), 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. // This includes pseudo-elements.
SpecificFragmentInfo::Generic 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. // Switch on display and floatedness.
match (display, float, positioning) { match (display, float, positioning) {
@ -1288,6 +1292,7 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
None | None |
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLImageElement))) => true, 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::HTMLObjectElement))) => self.has_object_data(),
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(HTMLElementTypeId::HTMLCanvasElement))) => true,
Some(NodeTypeId::Element(_)) => false, Some(NodeTypeId::Element(_)) => false,
} }
} }

View file

@ -11,6 +11,7 @@
#![deny(unsafe_blocks)] #![deny(unsafe_blocks)]
use block::BlockFlow; use block::BlockFlow;
use canvas::canvas_paint_task::CanvasMsg::SendPixelContents;
use context::LayoutContext; use context::LayoutContext;
use flow::{mod, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER}; use flow::{mod, Flow, IS_ABSOLUTELY_POSITIONED, NEEDS_LAYER};
use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo}; use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo};
@ -32,12 +33,14 @@ use gfx::display_list::TextOrientation;
use gfx::display_list::{SolidColorDisplayItem}; use gfx::display_list::{SolidColorDisplayItem};
use gfx::display_list::{StackingContext, TextDisplayItem}; use gfx::display_list::{StackingContext, TextDisplayItem};
use gfx::paint_task::PaintLayer; use gfx::paint_task::PaintLayer;
use png;
use png::PixelsByColorType;
use servo_msg::compositor_msg::ScrollPolicy; use servo_msg::compositor_msg::ScrollPolicy;
use servo_msg::constellation_msg::Msg as ConstellationMsg; use servo_msg::constellation_msg::Msg as ConstellationMsg;
use servo_msg::constellation_msg::ConstellationChan; use servo_msg::constellation_msg::ConstellationChan;
use servo_net::image::holder::ImageHolder; use servo_net::image::holder::ImageHolder;
use servo_util::cursor::Cursor; 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::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize};
use servo_util::opts; use servo_util::opts;
use std::default::Default; use std::default::Default;
@ -862,6 +865,37 @@ impl FragmentDisplayListBuilding for Fragment {
debug!("(building display list) no image :("); 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::<Arc<Vec<u8>>>();
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));
}
} }
} }

View file

@ -6,6 +6,7 @@
#![deny(unsafe_blocks)] #![deny(unsafe_blocks)]
use canvas::canvas_paint_task::CanvasMsg;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use construct::FlowConstructor; use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
@ -128,6 +129,7 @@ pub enum SpecificFragmentInfo {
Generic, Generic,
Iframe(Box<IframeFragmentInfo>), Iframe(Box<IframeFragmentInfo>),
Image(Box<ImageFragmentInfo>), Image(Box<ImageFragmentInfo>),
Canvas(Box<CanvasFragmentInfo>),
/// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was /// A hypothetical box (see CSS 2.1 § 10.3.7) for an absolutely-positioned block that was
/// declared with `display: inline;`. /// declared with `display: inline;`.
@ -156,6 +158,7 @@ impl SpecificFragmentInfo {
| SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableRow
| SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::TableWrapper
| SpecificFragmentInfo::UnscannedText(_) | SpecificFragmentInfo::UnscannedText(_)
| SpecificFragmentInfo::Canvas(_)
| SpecificFragmentInfo::Generic => return RestyleDamage::empty(), | SpecificFragmentInfo::Generic => return RestyleDamage::empty(),
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref, SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref,
SpecificFragmentInfo::InlineBlock(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 { pub fn get_type(&self) -> &'static str {
match *self { match *self {
SpecificFragmentInfo::Canvas(_) => "SpecificFragmentInfo::Canvas",
SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic", SpecificFragmentInfo::Generic => "SpecificFragmentInfo::Generic",
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe", SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image", SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
@ -217,17 +221,40 @@ impl InlineBlockFragmentInfo {
} }
} }
#[deriving(Clone)]
pub struct CanvasFragmentInfo {
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub renderer: Option<Arc<Mutex<Sender<CanvasMsg>>>>,
}
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. /// A fragment that represents a replaced content image and its accompanying borders, shadows, etc.
#[deriving(Clone)] #[deriving(Clone)]
pub struct ImageFragmentInfo { pub struct ImageFragmentInfo {
/// The image held within this fragment. /// The image held within this fragment.
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
pub image: ImageHolder<UntrustedNodeAddress>, pub image: ImageHolder<UntrustedNodeAddress>,
pub for_node: UntrustedNodeAddress,
pub computed_inline_size: Option<Au>,
pub computed_block_size: Option<Au>,
pub dom_inline_size: Option<Au>,
pub dom_block_size: Option<Au>,
pub writing_mode_is_vertical: bool,
} }
impl ImageFragmentInfo { impl ImageFragmentInfo {
@ -247,15 +274,60 @@ impl ImageFragmentInfo {
}).and_then(|pixels| Some(Au::from_px(pixels))) }).and_then(|pixels| Some(Au::from_px(pixels)))
} }
let is_vertical = node.style().writing_mode.is_vertical(); ImageFragmentInfo {
let dom_width = convert_length(node, &atom!("width")); replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
let dom_height = convert_length(node, &atom!("height")); 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<Au>,
pub computed_block_size: Option<Au>,
pub dom_inline_size: Option<Au>,
pub dom_block_size: Option<Au>,
pub writing_mode_is_vertical: bool,
}
impl ReplacedImageFragmentInfo {
pub fn new(node: &ThreadSafeLayoutNode,
dom_width: Option<Au>,
dom_height: Option<Au>) -> ReplacedImageFragmentInfo {
let is_vertical = node.style().writing_mode.is_vertical();
let opaque_node: OpaqueNode = OpaqueNodeMethods::from_thread_safe_layout_node(node); let opaque_node: OpaqueNode = OpaqueNodeMethods::from_thread_safe_layout_node(node);
let untrusted_node: UntrustedNodeAddress = opaque_node.to_untrusted_node_address(); let untrusted_node: UntrustedNodeAddress = opaque_node.to_untrusted_node_address();
ImageFragmentInfo { ReplacedImageFragmentInfo {
image: ImageHolder::new(image_url, local_image_cache),
for_node: untrusted_node, for_node: untrusted_node,
computed_inline_size: None, computed_inline_size: None,
computed_block_size: None, computed_block_size: None,
@ -275,18 +347,6 @@ impl ImageFragmentInfo {
self.computed_block_size.expect("image block_size is not computed yet!") 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. // Return used value for inline-size or block-size.
// //
// `dom_length`: inline-size or block-size as specified in the `img` tag. // `dom_length`: inline-size or block-size as specified in the `img` tag.
@ -319,16 +379,101 @@ impl ImageFragmentInfo {
}) })
} }
/// Tile an image pub fn calculate_replaced_inline_size(&mut self,
pub fn tile_image(position: &mut Au, size: &mut Au, style: ComputedValues,
virtual_position: Au, image_size: u32) { noncontent_inline_size: Au,
let image_size = image_size as int; container_inline_size: Au,
let delta_pixels = geometry::to_px(virtual_position - *position); fragment_inline_size: Au,
let tile_count = (delta_pixels + image_size - 1) / image_size; fragment_block_size: Au) -> Au {
let offset = Au::from_px(image_size * tile_count);
let new_position = virtual_position - offset; let style_inline_size = style.content_inline_size();
*size = *position - new_position + *size; let style_block_size = style.content_block_size();
*position = new_position; 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) fn quantities_included_in_intrinsic_inline_size(&self)
-> QuantitiesIncludedInIntrinsicInlineSizes { -> QuantitiesIncludedInIntrinsicInlineSizes {
match self.specific { match self.specific {
SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Generic |
SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Image(_) |
@ -1000,6 +1146,13 @@ impl Fragment {
preferred_inline_size: image_inline_size, 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) => { SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let range = &text_fragment_info.range; let range = &text_fragment_info.range;
let min_line_inline_size = text_fragment_info.run.min_width_for_range(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::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0), 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) => { 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) => { SpecificFragmentInfo::ScannedText(ref text_fragment_info) => {
let (range, run) = (&text_fragment_info.range, &text_fragment_info.run); let (range, run) = (&text_fragment_info.range, &text_fragment_info.run);
@ -1066,7 +1222,10 @@ impl Fragment {
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0), SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0),
SpecificFragmentInfo::Image(ref image_fragment_info) => { 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(_) => { SpecificFragmentInfo::ScannedText(_) => {
// Compute the block-size based on the line-block-size and font size. // 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) pub fn find_split_info_by_new_line(&self)
-> Option<(SplitInfo, Option<SplitInfo>, Arc<Box<TextRun>> /* TODO(bjz): remove */)> { -> Option<(SplitInfo, Option<SplitInfo>, Arc<Box<TextRun>> /* TODO(bjz): remove */)> {
match self.specific { 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::TableRow | SpecificFragmentInfo::TableWrapper => None,
SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not need to split"), SpecificFragmentInfo::TableColumn(_) => panic!("Table column fragments do not need to split"),
SpecificFragmentInfo::UnscannedText(_) => panic!("Unscanned text fragments should have been scanned by now!"), 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 /// Assigns replaced inline-size, padding, and margins for this fragment only if it is replaced
/// content per CSS 2.1 § 10.3.2. /// 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 { match self.specific {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell | SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell |
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return, SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableWrapper => return,
@ -1308,16 +1467,11 @@ impl Fragment {
SpecificFragmentInfo::UnscannedText(_) => { SpecificFragmentInfo::UnscannedText(_) => {
panic!("Unscanned text fragments should have been scanned by now!") 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(_) => {} SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {}
}; };
let style_inline_size = self.style().content_inline_size(); let style = self.style().clone();
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 noncontent_inline_size = self.border_padding.inline_start_end(); let noncontent_inline_size = self.border_padding.inline_start_end();
match self.specific { match self.specific {
@ -1341,49 +1495,24 @@ impl Fragment {
self.border_box.size.inline = info.content_size.inline + noncontent_inline_size self.border_box.size.inline = info.content_size.inline + noncontent_inline_size
} }
SpecificFragmentInfo::Image(ref mut image_fragment_info) => { SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
// TODO(ksh8281): compute border,margin let fragment_inline_size = image_fragment_info.image_inline_size();
let inline_size = ImageFragmentInfo::style_length( let fragment_block_size = image_fragment_info.image_block_size();
style_inline_size, self.border_box.size.inline = image_fragment_info.replaced_image_fragment_info.
image_fragment_info.dom_inline_size, calculate_replaced_inline_size(style,
container_inline_size); noncontent_inline_size,
container_inline_size,
let inline_size = match inline_size { fragment_inline_size,
MaybeAuto::Auto => { fragment_block_size);
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)
} }
}, SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
MaybeAuto::Specified(w) => w, 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.
let inline_size = ImageFragmentInfo::clamp_size(inline_size, calculate_replaced_inline_size(style,
style_min_inline_size, noncontent_inline_size,
style_max_inline_size, container_inline_size,
container_inline_size); fragment_inline_size,
fragment_block_size);
self.border_box.size.inline = inline_size + noncontent_inline_size;
image_fragment_info.computed_inline_size = Some(inline_size);
} }
_ => panic!("this case should have been handled above"), _ => panic!("this case should have been handled above"),
} }
@ -1401,42 +1530,33 @@ impl Fragment {
SpecificFragmentInfo::UnscannedText(_) => { SpecificFragmentInfo::UnscannedText(_) => {
panic!("Unscanned text fragments should have been scanned by now!") 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(_) => {} SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {}
} }
let style_block_size = self.style().content_block_size(); let style = self.style().clone();
let style_min_block_size = self.style().min_block_size();
let style_max_block_size = self.style().max_block_size();
let noncontent_block_size = self.border_padding.block_start_end(); let noncontent_block_size = self.border_padding.block_start_end();
match self.specific { match self.specific {
SpecificFragmentInfo::Image(ref mut image_fragment_info) => { SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
// TODO(ksh8281): compute border,margin,padding let fragment_inline_size = image_fragment_info.image_inline_size();
let inline_size = image_fragment_info.computed_inline_size(); let fragment_block_size = image_fragment_info.image_block_size();
let block_size = ImageFragmentInfo::style_length( self.border_box.size.block = image_fragment_info.replaced_image_fragment_info.
style_block_size, calculate_replaced_block_size(style,
image_fragment_info.dom_block_size, noncontent_block_size,
containing_block_block_size); containing_block_block_size,
fragment_inline_size,
let block_size = match block_size { fragment_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
} }
}; SpecificFragmentInfo::Canvas(ref mut canvas_fragment_info) => {
let fragment_inline_size = canvas_fragment_info.canvas_inline_size();
let block_size = ImageFragmentInfo::clamp_size(block_size, style_min_block_size, let fragment_block_size = canvas_fragment_info.canvas_block_size();
style_max_block_size, self.border_box.size.block = canvas_fragment_info.replaced_image_fragment_info.
Au(0)); calculate_replaced_block_size(style,
noncontent_block_size,
image_fragment_info.computed_block_size = Some(block_size); containing_block_block_size,
self.border_box.size.block = block_size + noncontent_block_size fragment_inline_size,
fragment_block_size);
} }
SpecificFragmentInfo::ScannedText(ref info) => { SpecificFragmentInfo::ScannedText(ref info) => {
// Scanned text fragments' content block-sizes are calculated by the text run // 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 { pub fn inline_metrics(&self, layout_context: &LayoutContext) -> InlineMetrics {
match self.specific { match self.specific {
SpecificFragmentInfo::Image(ref image_fragment_info) => { 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 { InlineMetrics {
block_size_above_baseline: computed_block_size + self.border_padding.block_start_end(), block_size_above_baseline: computed_block_size + self.border_padding.block_start_end(),
depth_below_baseline: Au(0), depth_below_baseline: Au(0),
@ -1538,6 +1658,7 @@ impl Fragment {
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::TableWrapper => false, SpecificFragmentInfo::TableWrapper => false,
SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Generic |
SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Image(_) |

View file

@ -13,12 +13,14 @@
extern crate log; extern crate log;
extern crate cssparser; extern crate cssparser;
extern crate canvas;
extern crate geom; extern crate geom;
extern crate gfx; extern crate gfx;
extern crate layout_traits; extern crate layout_traits;
extern crate script; extern crate script;
extern crate script_traits; extern crate script_traits;
extern crate serialize; extern crate serialize;
extern crate png;
extern crate style; extern crate style;
#[phase(plugin)] #[phase(plugin)]
extern crate "plugins" as servo_plugins; extern crate "plugins" as servo_plugins;

View file

@ -30,6 +30,7 @@
//! o Instead of `html_element_in_html_document()`, use //! o Instead of `html_element_in_html_document()`, use
//! `html_element_in_html_document_for_layout()`. //! `html_element_in_html_document_for_layout()`.
use canvas::canvas_paint_task::CanvasMsg;
use context::SharedLayoutContext; use context::SharedLayoutContext;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use incremental::RestyleDamage; use incremental::RestyleDamage;
@ -39,12 +40,13 @@ use util::{PrivateLayoutData};
use cssparser::RGBA; use cssparser::RGBA;
use gfx::display_list::OpaqueNode; use gfx::display_list::OpaqueNode;
use script::dom::bindings::codegen::InheritTypes::{ElementCast, HTMLIFrameElementCast}; 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::codegen::InheritTypes::{HTMLTextAreaElementCast, NodeCast, TextCast};
use script::dom::bindings::js::JS; use script::dom::bindings::js::JS;
use script::dom::element::{Element, ElementTypeId}; use script::dom::element::{Element, ElementTypeId};
use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers}; use script::dom::element::{LayoutElementHelpers, RawLayoutElementHelpers};
use script::dom::htmlelement::HTMLElementTypeId; use script::dom::htmlelement::HTMLElementTypeId;
use script::dom::htmlcanvaselement::{HTMLCanvasElement, LayoutHTMLCanvasElementHelpers};
use script::dom::htmliframeelement::HTMLIFrameElement; use script::dom::htmliframeelement::HTMLIFrameElement;
use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers; use script::dom::htmlimageelement::LayoutHTMLImageElementHelpers;
use script::dom::htmlinputelement::LayoutHTMLInputElementHelpers; use script::dom::htmlinputelement::LayoutHTMLInputElementHelpers;
@ -112,6 +114,27 @@ pub trait TLayoutNode {
} }
} }
fn get_renderer(&self) -> Option<Sender<CanvasMsg>> {
unsafe {
let canvas_element: Option<JS<HTMLCanvasElement>> = 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<JS<HTMLCanvasElement>> = HTMLCanvasElementCast::to_js(self.get_jsmanaged());
canvas_element.unwrap().get_canvas_width()
}
}
fn get_canvas_height(&self) -> u32 {
unsafe {
let canvas_element: Option<JS<HTMLCanvasElement>> = 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 /// If this node is an iframe element, returns its pipeline and subpage IDs. If this node is
/// not an iframe element, fails. /// not an iframe element, fails.
fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) { fn iframe_pipeline_and_subpage_ids(&self) -> (PipelineId, SubpageId) {

View file

@ -44,6 +44,16 @@ impl CanvasRenderingContext2D {
} }
} }
pub trait LayoutCanvasRenderingContext2DHelpers {
unsafe fn get_renderer(&self) -> Sender<CanvasMsg>;
}
impl LayoutCanvasRenderingContext2DHelpers for JS<CanvasRenderingContext2D> {
unsafe fn get_renderer(&self) -> Sender<CanvasMsg> {
(*self.unsafe_get()).renderer.clone()
}
}
impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> { impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D> {
fn Canvas(self) -> Temporary<HTMLCanvasElement> { fn Canvas(self) -> Temporary<HTMLCanvasElement> {
Temporary::new(self.canvas) Temporary::new(self.canvas)

View file

@ -2,6 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * 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::Attr;
use dom::attr::AttrHelpers; use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLCanvasElementBinding; 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::HTMLCanvasElementDerived;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast}; use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLElementCast};
use dom::bindings::global::GlobalRef; use dom::bindings::global::GlobalRef;
use dom::bindings::js::{MutNullableJS, JSRef, Temporary}; use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary};
use dom::canvasrenderingcontext2d::CanvasRenderingContext2D; use dom::canvasrenderingcontext2d::{CanvasRenderingContext2D, LayoutCanvasRenderingContext2DHelpers};
use dom::document::Document; use dom::document::Document;
use dom::element::{Element, AttributeHandlers}; use dom::element::{Element, AttributeHandlers};
use dom::eventtarget::{EventTarget, EventTargetTypeId}; use dom::eventtarget::{EventTarget, EventTargetTypeId};
@ -60,6 +61,27 @@ impl HTMLCanvasElement {
} }
} }
pub trait LayoutHTMLCanvasElementHelpers {
unsafe fn get_renderer(&self) -> Option<Sender<CanvasMsg>>;
unsafe fn get_canvas_width(&self) -> u32;
unsafe fn get_canvas_height(&self) -> u32;
}
impl LayoutHTMLCanvasElementHelpers for JS<HTMLCanvasElement> {
unsafe fn get_renderer(&self) -> Option<Sender<CanvasMsg>> {
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> { impl<'a> HTMLCanvasElementMethods for JSRef<'a, HTMLCanvasElement> {
fn Width(self) -> u32 { fn Width(self) -> u32 {
self.width.get() self.width.get()

View file

@ -26,7 +26,7 @@ dependencies = [
[[package]] [[package]]
name = "azure" name = "azure"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898"
dependencies = [ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "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)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",

2
ports/cef/Cargo.lock generated
View file

@ -27,7 +27,7 @@ dependencies = [
[[package]] [[package]]
name = "azure" name = "azure"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898"
dependencies = [ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "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)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",

2
ports/gonk/Cargo.lock generated
View file

@ -15,7 +15,7 @@ dependencies = [
[[package]] [[package]]
name = "azure" name = "azure"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-azure#e1a91efa633f155da89c6a1dadb0049d847b319d" source = "git+https://github.com/servo/rust-azure#f4a02f3f621b0a994a20d42e438371a87c62f898"
dependencies = [ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "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)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",