aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/gfx/display_list/mod.rs90
-rw-r--r--src/components/gfx/render_task.rs2
-rw-r--r--src/components/layout/fragment.rs21
-rw-r--r--src/components/layout/inline.rs11
-rw-r--r--src/components/layout/text.rs40
-rw-r--r--src/components/util/logical_geometry.rs5
6 files changed, 129 insertions, 40 deletions
diff --git a/src/components/gfx/display_list/mod.rs b/src/components/gfx/display_list/mod.rs
index ec80734c182..b50689422ac 100644
--- a/src/components/gfx/display_list/mod.rs
+++ b/src/components/gfx/display_list/mod.rs
@@ -21,7 +21,7 @@ use text::TextRun;
use collections::dlist::DList;
use collections::dlist;
-use geom::{Point2D, Rect, SideOffsets2D, Size2D};
+use geom::{Point2D, Rect, SideOffsets2D, Size2D, Matrix2D};
use libc::uintptr_t;
use servo_net::image::base::Image;
use servo_util::geometry::Au;
@@ -337,10 +337,11 @@ impl DisplayList {
/// Draws the display list into the given render context. The display list must be flattened
/// first for correct painting.
- pub fn draw_into_context(&self, render_context: &mut RenderContext) {
+ pub fn draw_into_context(&self, render_context: &mut RenderContext,
+ current_transform: &Matrix2D<AzFloat>) {
debug!("Beginning display list.");
for item in self.list.iter() {
- item.draw_into_context(render_context)
+ item.draw_into_context(render_context, current_transform)
}
debug!("Ending display list.");
}
@@ -483,6 +484,16 @@ pub struct TextDisplayItem {
/// The color of the text.
pub text_color: Color,
+
+ pub baseline_origin: Point2D<Au>,
+ pub orientation: TextOrientation,
+}
+
+#[deriving(Clone, Eq, PartialEq)]
+pub enum TextOrientation {
+ Upright,
+ SidewaysLeft,
+ SidewaysRight,
}
/// Renders an image.
@@ -560,7 +571,8 @@ impl<'a> Iterator<&'a DisplayItem> for DisplayItemIterator<'a> {
impl DisplayItem {
/// Renders this display item into the given render context.
- fn draw_into_context(&self, render_context: &mut RenderContext) {
+ fn draw_into_context(&self, render_context: &mut RenderContext,
+ current_transform: &Matrix2D<AzFloat>) {
// This should have been flattened to the content stacking level first.
assert!(self.base().level == ContentStackingLevel);
@@ -572,31 +584,61 @@ impl DisplayItem {
ClipDisplayItemClass(ref clip) => {
render_context.draw_push_clip(&clip.base.bounds);
for item in clip.children.iter() {
- (*item).draw_into_context(render_context);
+ (*item).draw_into_context(render_context, current_transform);
}
render_context.draw_pop_clip();
}
TextDisplayItemClass(ref text) => {
- debug!("Drawing text at {:?}.", text.base.bounds);
-
- // FIXME(pcwalton): Allocating? Why?
- let text_run = text.text_run.clone();
-
- let font = render_context.font_ctx.get_render_font_from_template(
- &text_run.font_template,
- text_run.pt_size,
- render_context.opts.render_backend);
- let font = font.borrow();
-
- let origin = text.base.bounds.origin;
- let baseline_origin = Point2D(origin.x, origin.y + text_run.font_metrics.ascent);
- {
- font.draw_text_into_context(render_context,
- &*text.text_run,
- &text.range,
- baseline_origin,
- text.text_color);
+ debug!("Drawing text at {}.", text.base.bounds);
+
+ // Optimization: Don’t set a transform matrix for upright text,
+ // and pass a strart point to `draw_text_into_context`.
+ // For sideways text, it’s easier to do the rotation such that its center
+ // (the baseline’s start point) is at (0, 0) coordinates.
+ let baseline_origin = match text.orientation {
+ Upright => text.baseline_origin,
+ SidewaysLeft => {
+ let x = text.baseline_origin.x.to_nearest_px() as AzFloat;
+ let y = text.baseline_origin.y.to_nearest_px() as AzFloat;
+ render_context.draw_target.set_transform(&current_transform.mul(
+ &Matrix2D::new(
+ 0., -1.,
+ 1., 0.,
+ x, y
+ )
+ ));
+ Zero::zero()
+ },
+ SidewaysRight => {
+ let x = text.baseline_origin.x.to_nearest_px() as AzFloat;
+ let y = text.baseline_origin.y.to_nearest_px() as AzFloat;
+ render_context.draw_target.set_transform(&current_transform.mul(
+ &Matrix2D::new(
+ 0., 1.,
+ -1., 0.,
+ x, y
+ )
+ ));
+ Zero::zero()
+ }
+ };
+
+ render_context.font_ctx.get_render_font_from_template(
+ &text.text_run.font_template,
+ text.text_run.pt_size,
+ render_context.opts.render_backend
+ ).borrow().draw_text_into_context(
+ render_context,
+ &*text.text_run,
+ &text.range,
+ baseline_origin,
+ text.text_color
+ );
+
+ // Undo the transform, only when we did one.
+ if text.orientation != Upright {
+ render_context.draw_target.set_transform(current_transform)
}
}
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs
index 710a08bff9e..2d7b8b5e2d7 100644
--- a/src/components/gfx/render_task.rs
+++ b/src/components/gfx/render_task.rs
@@ -352,7 +352,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
// Draw the display list.
profile(time::RenderingDrawingCategory, self.time_profiler_chan.clone(), || {
- display_list.draw_into_context(&mut ctx);
+ display_list.draw_into_context(&mut ctx, &matrix);
ctx.draw_target.flush();
});
}
diff --git a/src/components/layout/fragment.rs b/src/components/layout/fragment.rs
index e0c0b2f6e88..f00bb8a7f7c 100644
--- a/src/components/layout/fragment.rs
+++ b/src/components/layout/fragment.rs
@@ -29,6 +29,7 @@ use gfx::display_list::{ImageDisplayItemClass, LineDisplayItem};
use gfx::display_list::{LineDisplayItemClass, OpaqueNode, PseudoDisplayItemClass};
use gfx::display_list::{SolidColorDisplayItem, SolidColorDisplayItemClass, StackingLevel};
use gfx::display_list::{TextDisplayItem, TextDisplayItemClass};
+use gfx::display_list::{Upright, SidewaysLeft, SidewaysRight};
use gfx::font::FontStyle;
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::TextRun;
@@ -935,12 +936,31 @@ impl Fragment {
TableColumnFragment(_) => fail!("Shouldn't see table column fragments here."),
ScannedTextFragment(ref text_fragment) => {
// Create the text display item.
+ let orientation = if self.style.writing_mode.is_vertical() {
+ if self.style.writing_mode.is_sideways_left() {
+ SidewaysLeft
+ } else {
+ SidewaysRight
+ }
+ } else {
+ Upright
+ };
+
+ let metrics = &text_fragment.run.font_metrics;
+ let baseline_origin ={
+ let mut tmp = content_box.start;
+ tmp.b = tmp.b + metrics.ascent;
+ tmp.to_physical(self.style.writing_mode, container_size) + flow_origin
+ };
+
let text_display_item = box TextDisplayItem {
base: BaseDisplayItem::new(
absolute_content_box, self.node, ContentStackingLevel),
text_run: text_fragment.run.clone(),
range: text_fragment.range,
text_color: self.style().get_color().color.to_gfx_color(),
+ orientation: orientation,
+ baseline_origin: baseline_origin,
};
accumulator.push(display_list, TextDisplayItemClass(text_display_item));
@@ -965,7 +985,6 @@ impl Fragment {
let text_decorations =
self.style().get_inheritedtext()._servo_text_decorations_in_effect;
- let metrics = &text_fragment.run.font_metrics;
line(text_decorations.underline, || {
let mut rect = content_box.clone();
rect.start.b = rect.start.b + metrics.ascent - metrics.underline_offset;
diff --git a/src/components/layout/inline.rs b/src/components/layout/inline.rs
index bdbabe31f5e..c5157709c27 100644
--- a/src/components/layout/inline.rs
+++ b/src/components/layout/inline.rs
@@ -1100,13 +1100,10 @@ impl Flow for InlineFlow {
line_distance_from_flow_block_start = line_distance_from_flow_block_start + line.bounds.size.block;
} // End of `lines.each` loop.
- self.base.position.size.block =
- if self.lines.len() > 0 {
- self.lines.as_slice().last().get_ref().bounds.start.b +
- self.lines.as_slice().last().get_ref().bounds.size.block
- } else {
- Au::new(0)
- };
+ self.base.position.size.block = match self.lines.as_slice().last() {
+ Some(ref last_line) => last_line.bounds.start.b + last_line.bounds.size.block,
+ None => Au::new(0)
+ };
self.base.floats = scanner.floats();
self.base.floats.translate(LogicalSize::new(
diff --git a/src/components/layout/text.rs b/src/components/layout/text.rs
index 70b2cc7a3cc..e90272e218a 100644
--- a/src/components/layout/text.rs
+++ b/src/components/layout/text.rs
@@ -9,16 +9,16 @@
use flow::Flow;
use fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, UnscannedTextFragment};
-use gfx::font::{FontMetrics, FontStyle};
+use gfx::font::{FontMetrics, FontStyle, RunMetrics};
use gfx::font_context::FontContext;
use gfx::text::glyph::CharIndex;
use gfx::text::text_run::TextRun;
use gfx::text::util::{CompressWhitespaceNewline, transform_text, CompressNone};
use servo_util::geometry::Au;
-use servo_util::logical_geometry::LogicalSize;
+use servo_util::logical_geometry::{LogicalSize, WritingMode};
use servo_util::range::Range;
use style::ComputedValues;
-use style::computed_values::{font_family, line_height, white_space};
+use style::computed_values::{font_family, line_height, text_orientation, white_space};
use sync::Arc;
struct NewLinePositions {
@@ -150,8 +150,8 @@ impl TextRunScanner {
*text);
let range = Range::new(CharIndex(0), run.char_len());
let new_metrics = run.metrics_for_range(&range);
- let bounding_box_size = LogicalSize::from_physical(
- old_fragment.style.writing_mode, new_metrics.bounding_box.size);
+ let bounding_box_size = bounding_box_for_run_metrics(
+ &new_metrics, old_fragment.style.writing_mode);
let new_text_fragment_info = ScannedTextFragmentInfo::new(Arc::new(run), range);
let mut new_fragment = old_fragment.transform(
bounding_box_size, ScannedTextFragment(new_text_fragment_info));
@@ -234,8 +234,8 @@ impl TextRunScanner {
let new_text_fragment_info = ScannedTextFragmentInfo::new(run.get_ref().clone(), range);
let old_fragment = &in_fragments[i.to_uint()];
let new_metrics = new_text_fragment_info.run.metrics_for_range(&range);
- let bounding_box_size = LogicalSize::from_physical(
- old_fragment.style.writing_mode, new_metrics.bounding_box.size);
+ let bounding_box_size = bounding_box_for_run_metrics(
+ &new_metrics, old_fragment.style.writing_mode);
let mut new_fragment = old_fragment.transform(
bounding_box_size, ScannedTextFragment(new_text_fragment_info));
new_fragment.new_line_pos = new_line_positions[logical_offset.to_uint()].new_line_pos.clone();
@@ -251,6 +251,32 @@ impl TextRunScanner {
} // End of `flush_clump_to_list`.
}
+
+#[inline]
+fn bounding_box_for_run_metrics(metrics: &RunMetrics, writing_mode: WritingMode)
+ -> LogicalSize<Au> {
+
+ // This does nothing, but it will fail to build
+ // when more values are added to the `text-orientation` CSS property.
+ // This will be a reminder to update the code below.
+ let dummy: Option<text_orientation::T> = None;
+ match dummy {
+ Some(text_orientation::sideways_right) |
+ Some(text_orientation::sideways_left) |
+ Some(text_orientation::sideways) |
+ None => {}
+ }
+
+ // In vertical sideways or horizontal upgright text,
+ // the "width" of text metrics is always inline
+ // This will need to be updated when other text orientations are supported.
+ LogicalSize::new(
+ writing_mode,
+ metrics.bounding_box.size.width,
+ metrics.bounding_box.size.height)
+
+}
+
/// Returns the metrics of the font represented by the given `FontStyle`, respectively.
///
/// `#[inline]` because often the caller only needs a few fields from the font metrics.
diff --git a/src/components/util/logical_geometry.rs b/src/components/util/logical_geometry.rs
index e2cfde31f31..8f2356a5f88 100644
--- a/src/components/util/logical_geometry.rs
+++ b/src/components/util/logical_geometry.rs
@@ -41,6 +41,11 @@ impl WritingMode {
pub fn is_bidi_ltr(&self) -> bool {
!self.intersects(FlagRTL)
}
+
+ #[inline]
+ pub fn is_sideways_left(&self) -> bool {
+ self.intersects(FlagSidewaysLeft)
+ }
}
impl Show for WritingMode {