diff --git a/src/batch_builder.rs b/src/batch_builder.rs
index d9421a4e27..9858671641 100644
--- a/src/batch_builder.rs
+++ b/src/batch_builder.rs
@@ -80,11 +80,13 @@ impl<'a> BatchBuilder<'a> {
bottom_right: Point2D::new(u1, v1),
};
+ let uv_size = image_info.uv_rect.bottom_right - image_info.uv_rect.top_left;
+
let tile_params = TileParams {
- u0: image_info.u0,
- v0: image_info.v0,
- u_size: image_info.u1 - image_info.u0,
- v_size: image_info.v1 - image_info.v0,
+ u0: image_info.uv_rect.top_left.x,
+ v0: image_info.uv_rect.top_left.y,
+ u_size: uv_size.x,
+ v_size: uv_size.y,
};
clipper::clip_rect_to_combined_region(RectPosUv {
@@ -139,24 +141,16 @@ impl<'a> BatchBuilder<'a> {
for glyph in glyphs {
glyph_key.index = glyph.index;
let image_info = resource_cache.get_glyph(&glyph_key);
-
- if image_info.width > 0 && image_info.height > 0 {
- let x = glyph.x + image_info.user_x0 as f32 / device_pixel_ratio - blur_offset;
- let y = glyph.y - image_info.user_y0 as f32 / device_pixel_ratio - blur_offset;
- let width = image_info.width as f32 / device_pixel_ratio;
- let height = image_info.height as f32 / device_pixel_ratio;
-
- let uv = RectUv {
- top_left: Point2D::new(image_info.u0, image_info.v0),
- top_right: Point2D::new(image_info.u1, image_info.v0),
- bottom_left: Point2D::new(image_info.u0, image_info.v1),
- bottom_right: Point2D::new(image_info.u1, image_info.v1),
- };
+ if let Some(image_info) = image_info {
+ let x = glyph.x + image_info.user_data.x0 as f32 / device_pixel_ratio - blur_offset;
+ let y = glyph.y - image_info.user_data.y0 as f32 / device_pixel_ratio - blur_offset;
+ let width = image_info.rect.size.width as f32 / device_pixel_ratio;
+ let height = image_info.rect.size.height as f32 / device_pixel_ratio;
let rect = RectPosUv {
pos: Rect::new(Point2D::new(x, y),
Size2D::new(width, height)),
- uv: uv,
+ uv: image_info.uv_rect,
};
let rect_buffer = match text_batches.entry((image_info.texture_id,
@@ -199,28 +193,28 @@ impl<'a> BatchBuilder<'a> {
x0, y0,
color,
rect.uv.top_left.x, rect.uv.top_left.y,
- dummy_mask_image.u0, dummy_mask_image.v0,
+ dummy_mask_image.uv_rect.top_left.x, dummy_mask_image.uv_rect.top_left.y,
texture_index,
dummy_mask_image.texture_index));
vertex_buffer.push(PackedVertex::from_components(
x1, y0,
color,
rect.uv.top_right.x, rect.uv.top_right.y,
- dummy_mask_image.u1, dummy_mask_image.v0,
+ dummy_mask_image.uv_rect.top_right.x, dummy_mask_image.uv_rect.top_right.y,
texture_index,
dummy_mask_image.texture_index));
vertex_buffer.push(PackedVertex::from_components(
x0, y1,
color,
rect.uv.bottom_left.x, rect.uv.bottom_left.y,
- dummy_mask_image.u0, dummy_mask_image.v1,
+ dummy_mask_image.uv_rect.bottom_left.x, dummy_mask_image.uv_rect.bottom_left.y,
texture_index,
dummy_mask_image.texture_index));
vertex_buffer.push(PackedVertex::from_components(
x1, y1,
color,
rect.uv.bottom_right.x, rect.uv.bottom_right.y,
- dummy_mask_image.v0, dummy_mask_image.v1,
+ dummy_mask_image.uv_rect.bottom_right.x, dummy_mask_image.uv_rect.bottom_right.y,
texture_index,
dummy_mask_image.texture_index));
}
@@ -266,17 +260,10 @@ impl<'a> BatchBuilder<'a> {
return
}
- let uv = RectUv {
- top_left: Point2D::new(image_info.u0, image_info.v0),
- top_right: Point2D::new(image_info.u1, image_info.v0),
- bottom_left: Point2D::new(image_info.u0, image_info.v1),
- bottom_right: Point2D::new(image_info.u1, image_info.v1),
- };
-
clipper::clip_rect_to_combined_region(
RectPosUv {
pos: *rect,
- uv: uv,
+ uv: image_info.uv_rect,
},
&mut clip_buffers.sh_clip_buffers,
&mut clip_buffers.rect_pos_uv,
diff --git a/src/internal_types.rs b/src/internal_types.rs
index ffe1554969..e285c9b5ec 100644
--- a/src/internal_types.rs
+++ b/src/internal_types.rs
@@ -405,15 +405,16 @@ impl
ClipRectToRegionResult
{
pub fn muv_for_position(&self, position: &Point2D, mask: &TextureCacheItem)
-> Point2D {
- let mask_uv_size = Size2D::new(mask.u1 - mask.u0, mask.v1 - mask.v0);
+ let mask_uv_size = Size2D::new(mask.uv_rect.bottom_right.x - mask.uv_rect.top_left.x,
+ mask.uv_rect.bottom_right.y - mask.uv_rect.top_left.y);
let mask_result = match self.mask_result {
None => return Point2D::new(0.0, 0.0),
Some(ref mask_result) => mask_result,
};
let muv_rect =
- Rect::new(Point2D::new(mask.u0 + mask_result.muv_rect.origin.x * mask_uv_size.width,
- mask.v0 + mask_result.muv_rect.origin.y * mask_uv_size.height),
+ Rect::new(Point2D::new(mask.uv_rect.top_left.x + mask_result.muv_rect.origin.x * mask_uv_size.width,
+ mask.uv_rect.top_left.y + mask_result.muv_rect.origin.y * mask_uv_size.height),
Size2D::new(mask_result.muv_rect.size.width * mask_uv_size.width,
mask_result.muv_rect.size.height * mask_uv_size.height));
let position_rect = &mask_result.position_rect;
@@ -572,34 +573,34 @@ impl RectUv {
match rotation_angle {
BasicRotationAngle::Upright => {
RectUv {
- top_left: Point2D::new(image.u0, image.v0),
- top_right: Point2D::new(image.u1, image.v0),
- bottom_right: Point2D::new(image.u1, image.v1),
- bottom_left: Point2D::new(image.u0, image.v1),
+ top_left: image.uv_rect.top_left,
+ top_right: image.uv_rect.top_right,
+ bottom_right: image.uv_rect.bottom_right,
+ bottom_left: image.uv_rect.bottom_left,
}
}
BasicRotationAngle::Clockwise90 => {
RectUv {
- top_right: Point2D::new(image.u0, image.v0),
- top_left: Point2D::new(image.u1, image.v0),
- bottom_left: Point2D::new(image.u1, image.v1),
- bottom_right: Point2D::new(image.u0, image.v1),
+ top_right: image.uv_rect.top_left,
+ top_left: image.uv_rect.top_right,
+ bottom_left: image.uv_rect.bottom_right,
+ bottom_right: image.uv_rect.bottom_left,
}
}
BasicRotationAngle::Clockwise180 => {
RectUv {
- bottom_right: Point2D::new(image.u0, image.v0),
- bottom_left: Point2D::new(image.u1, image.v0),
- top_left: Point2D::new(image.u1, image.v1),
- top_right: Point2D::new(image.u0, image.v1),
+ bottom_right: image.uv_rect.top_left,
+ bottom_left: image.uv_rect.top_right,
+ top_left: image.uv_rect.bottom_right,
+ top_right: image.uv_rect.bottom_left,
}
}
BasicRotationAngle::Clockwise270 => {
RectUv {
- bottom_left: Point2D::new(image.u0, image.v0),
- bottom_right: Point2D::new(image.u1, image.v0),
- top_right: Point2D::new(image.u1, image.v1),
- top_left: Point2D::new(image.u0, image.v1),
+ bottom_left: image.uv_rect.top_left,
+ bottom_right: image.uv_rect.top_right,
+ top_right: image.uv_rect.bottom_right,
+ top_left: image.uv_rect.bottom_left,
}
}
}
diff --git a/src/resource_cache.rs b/src/resource_cache.rs
index dc4a1bf6c4..2562f81dd5 100644
--- a/src/resource_cache.rs
+++ b/src/resource_cache.rs
@@ -32,7 +32,6 @@ struct ImageResource {
}
struct GlyphRasterJob {
- image_id: TextureCacheItemId,
glyph_key: GlyphKey,
result: Option,
}
@@ -43,7 +42,7 @@ struct CachedImageInfo {
}
pub struct ResourceCache {
- cached_glyphs: HashMap>,
+ cached_glyphs: HashMap, DefaultState>,
cached_rasters: HashMap>,
cached_images: HashMap>,
@@ -201,13 +200,10 @@ impl ResourceCache {
// Update texture cache with any newly rasterized glyphs.
resource_list.for_each_glyph(|glyph_key| {
if !self.cached_glyphs.contains_key(glyph_key) {
- let image_id = self.texture_cache.new_item_id();
self.pending_raster_jobs.push(GlyphRasterJob {
- image_id: image_id,
glyph_key: glyph_key.clone(),
result: None,
});
- self.cached_glyphs.insert(glyph_key.clone(), image_id);
}
});
}
@@ -223,32 +219,39 @@ impl ResourceCache {
// Add completed raster jobs to the texture cache
for job in self.pending_raster_jobs.drain(..) {
let result = job.result.expect("Failed to rasterize the glyph?");
- let texture_width;
- let texture_height;
- let insert_op;
- match job.glyph_key.blur_radius {
- Au(0) => {
- texture_width = result.width;
- texture_height = result.height;
- insert_op = TextureInsertOp::Blit(result.bytes);
- }
- blur_radius => {
- let blur_radius_px = f32::ceil(blur_radius.to_f32_px() * self.device_pixel_ratio)
- as u32;
- texture_width = result.width + blur_radius_px * BLUR_INFLATION_FACTOR;
- texture_height = result.height + blur_radius_px * BLUR_INFLATION_FACTOR;
- insert_op = TextureInsertOp::Blur(result.bytes,
- Size2D::new(result.width, result.height),
- blur_radius);
+ let image_id = if result.width > 0 && result.height > 0 {
+ let image_id = self.texture_cache.new_item_id();
+ let texture_width;
+ let texture_height;
+ let insert_op;
+ match job.glyph_key.blur_radius {
+ Au(0) => {
+ texture_width = result.width;
+ texture_height = result.height;
+ insert_op = TextureInsertOp::Blit(result.bytes);
+ }
+ blur_radius => {
+ let blur_radius_px = f32::ceil(blur_radius.to_f32_px() * self.device_pixel_ratio)
+ as u32;
+ texture_width = result.width + blur_radius_px * BLUR_INFLATION_FACTOR;
+ texture_height = result.height + blur_radius_px * BLUR_INFLATION_FACTOR;
+ insert_op = TextureInsertOp::Blur(result.bytes,
+ Size2D::new(result.width, result.height),
+ blur_radius);
+ }
}
- }
- self.texture_cache.insert(job.image_id,
- result.left,
- result.top,
- texture_width,
- texture_height,
- ImageFormat::RGBA8,
- insert_op);
+ self.texture_cache.insert(image_id,
+ result.left,
+ result.top,
+ texture_width,
+ texture_height,
+ ImageFormat::RGBA8,
+ insert_op);
+ Some(image_id)
+ } else {
+ None
+ };
+ self.cached_glyphs.insert(job.glyph_key, image_id);
}
}
@@ -301,9 +304,9 @@ impl ResourceCache {
}
#[inline]
- pub fn get_glyph(&self, glyph_key: &GlyphKey) -> &TextureCacheItem {
+ pub fn get_glyph(&self, glyph_key: &GlyphKey) -> Option<&TextureCacheItem> {
let image_id = self.cached_glyphs[glyph_key];
- self.texture_cache.get(image_id)
+ image_id.map(|image_id| self.texture_cache.get(image_id))
}
#[inline]
diff --git a/src/texture_cache.rs b/src/texture_cache.rs
index faeee236cd..d6c102b561 100644
--- a/src/texture_cache.rs
+++ b/src/texture_cache.rs
@@ -5,7 +5,7 @@ use fnv::FnvHasher;
use freelist::{FreeList, FreeListItem, FreeListItemId};
use internal_types::{TextureTarget, TextureUpdate, TextureUpdateOp, TextureUpdateDetails};
use internal_types::{RasterItem, RenderTargetMode, TextureImage, TextureUpdateList};
-use internal_types::{BasicRotationAngle};
+use internal_types::{BasicRotationAngle, RectUv};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_state::DefaultState;
@@ -188,44 +188,44 @@ impl TexturePage {
}
}
+// TODO(gw): This is used to store data specific to glyphs.
+// Perhaps find a better place to store it.
+#[derive(Debug, Clone)]
+pub struct TextureCacheItemUserData {
+ pub x0: i32,
+ pub y0: i32,
+}
+
#[derive(Debug, Clone)]
pub struct TextureCacheItem {
- pub u0: f32, // todo(gw): don't precalc these?
- pub v0: f32,
- pub u1: f32,
- pub v1: f32,
- pub user_x0: i32,
- pub user_y0: i32,
- pub page_x0: u32,
- pub page_y0: u32,
- pub width: u32,
- pub height: u32,
- pub texture_id: TextureId, // todo(gw): can this ever get invalidated? (page defragmentation?)
- pub format: ImageFormat,
+ pub user_data: TextureCacheItemUserData,
+ pub rect: Rect,
+ pub uv_rect: RectUv,
+ pub texture_id: TextureId,
pub texture_index: TextureIndex,
}
// Structure squat the width/height fields to maintain the free list information :)
impl FreeListItem for TextureCacheItem {
fn next_free_id(&self) -> Option {
- if self.width == 0 {
- debug_assert!(self.height == 0);
+ if self.rect.size.width == 0 {
+ debug_assert!(self.rect.size.height == 0);
None
} else {
- debug_assert!(self.width == 1);
- Some(FreeListItemId::new(self.height))
+ debug_assert!(self.rect.size.width == 1);
+ Some(FreeListItemId::new(self.rect.size.height))
}
}
fn set_next_free_id(&mut self, id: Option) {
match id {
Some(id) => {
- self.width = 1;
- self.height = id.value();
+ self.rect.size.width = 1;
+ self.rect.size.height = id.value();
}
None => {
- self.width = 0;
- self.height = 0;
+ self.rect.size.width = 0;
+ self.rect.size.height = 0;
}
}
}
@@ -234,27 +234,19 @@ impl FreeListItem for TextureCacheItem {
impl TextureCacheItem {
fn new(texture_id: TextureId,
texture_index: TextureIndex,
- format: ImageFormat,
user_x0: i32, user_y0: i32,
- page_x0: u32, page_y0: u32,
- width: u32, height: u32,
- u0: f32, v0: f32,
- u1: f32, v1: f32)
+ rect: Rect,
+ uv_rect: RectUv)
-> TextureCacheItem {
TextureCacheItem {
texture_id: texture_id,
texture_index: texture_index,
- u0: u0,
- v0: v0,
- u1: u1,
- v1: v1,
- user_x0: user_x0,
- user_y0: user_y0,
- page_x0: page_x0,
- page_y0: page_y0,
- width: width,
- height: height,
- format: format,
+ uv_rect: uv_rect,
+ user_data: TextureCacheItemUserData {
+ x0: user_x0,
+ y0: user_y0,
+ },
+ rect: rect,
}
}
@@ -263,10 +255,12 @@ impl TextureCacheItem {
TextureImage {
texture_id: self.texture_id,
texture_index: self.texture_index,
- texel_uv: Rect::new(Point2D::new(self.u0, self.v0), Size2D::new(self.u1 - self.u0,
- self.v1 - self.v0)),
- pixel_uv: Point2D::new((self.u0 * texture_size) as u32,
- (self.v0 * texture_size) as u32),
+ texel_uv: Rect::new(Point2D::new(self.uv_rect.top_left.x,
+ self.uv_rect.top_left.y),
+ Size2D::new(self.uv_rect.bottom_right.x - self.uv_rect.top_left.x,
+ self.uv_rect.bottom_right.y - self.uv_rect.top_left.y)),
+ pixel_uv: Point2D::new((self.uv_rect.top_left.x * texture_size) as u32,
+ (self.uv_rect.top_left.y * texture_size) as u32),
}
}
}
@@ -336,18 +330,18 @@ impl TextureCache {
// how the raster_jobs code works.
pub fn new_item_id(&mut self) -> TextureCacheItemId {
let new_item = TextureCacheItem {
- u0: 0.0,
- v0: 0.0,
- u1: 0.0,
- v1: 0.0,
- user_x0: 0,
- user_y0: 0,
- page_x0: 0,
- page_y0: 0,
- width: 0,
- height: 0,
+ uv_rect: RectUv {
+ top_left: Point2D::zero(),
+ top_right: Point2D::zero(),
+ bottom_left: Point2D::zero(),
+ bottom_right: Point2D::zero(),
+ },
+ user_data: TextureCacheItemUserData {
+ x0: 0,
+ y0: 0,
+ },
+ rect: Rect::zero(),
texture_id: TextureId::invalid(),
- format: ImageFormat::Invalid,
texture_index: TextureIndex(0),
};
self.items.insert(new_item)
@@ -453,12 +447,15 @@ impl TextureCache {
.expect("TODO: Handle running out of texture ids!");
let cache_item = TextureCacheItem::new(texture_id,
TextureIndex(0),
- format,
x0, y0,
- 0, 0,
- width, height,
- 0.0, 0.0,
- 1.0, 1.0);
+ Rect::new(Point2D::zero(),
+ Size2D::new(width, height)),
+ RectUv {
+ top_left: Point2D::new(0.0, 0.0),
+ top_right: Point2D::new(1.0, 0.0),
+ bottom_left: Point2D::new(0.0, 1.0),
+ bottom_right: Point2D::new(1.0, 1.0),
+ });
*self.items.get_mut(image_id) = cache_item;
return AllocationResult {
@@ -486,12 +483,15 @@ impl TextureCache {
let v1 = v0 + height as f32 / page.texture_size as f32;
let cache_item = TextureCacheItem::new(page.texture_id,
page.texture_index,
- format,
x0, y0,
- tx0, ty0,
- width, height,
- u0, v0,
- u1, v1);
+ Rect::new(Point2D::new(tx0, ty0),
+ Size2D::new(width, height)),
+ RectUv {
+ top_left: Point2D::new(u0, v0),
+ top_right: Point2D::new(u1, v0),
+ bottom_left: Point2D::new(u0, v1),
+ bottom_right: Point2D::new(u1, v1)
+ });
*self.items.get_mut(image_id) = cache_item;
// TODO(pcwalton): Select a texture index if we're using texture arrays.
@@ -577,17 +577,16 @@ impl TextureCache {
image_id: TextureCacheItemId,
width: u32,
height: u32,
- format: ImageFormat,
+ _format: ImageFormat,
bytes: Vec) {
let existing_item = self.items.get(image_id);
// TODO(gw): Handle updates to size/format!
- debug_assert!(existing_item.width == width);
- debug_assert!(existing_item.height == height);
- debug_assert!(existing_item.format == format);
+ debug_assert!(existing_item.rect.size.width == width);
+ debug_assert!(existing_item.rect.size.height == height);
- let op = TextureUpdateOp::Update(existing_item.page_x0,
- existing_item.page_y0,
+ let op = TextureUpdateOp::Update(existing_item.rect.origin.x,
+ existing_item.rect.origin.y,
width,
height,
TextureUpdateDetails::Blit(bytes));