mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 1463416 - Update webrender to cset 63c71ca9bbe4dec0ebc9c9bc8ab65b06a6b40641. r=Gankro
MozReview-Commit-ID: 21gmlBlV8En --HG-- extra : rebase_source : 89e3746c4254b9a20ca811be6419eb3901b4f319
This commit is contained in:
parent
08f7efc25a
commit
ca48941951
@ -23,7 +23,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_resources: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
|
@ -34,7 +34,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_resources: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
|
@ -182,7 +182,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
_: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
@ -201,7 +201,7 @@ impl Example for App {
|
||||
);
|
||||
|
||||
let image_mask_key = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
image_mask_key,
|
||||
ImageDescriptor::new(2, 2, ImageFormat::R8, true, false),
|
||||
ImageData::new(vec![0, 80, 180, 255]),
|
||||
|
@ -16,7 +16,7 @@ use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||
use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, RenderApi, ResourceUpdates};
|
||||
use webrender::api::{self, DisplayListBuilder, DocumentId, PipelineId, RenderApi, Transaction};
|
||||
|
||||
// This example shows how to implement a very basic BlobImageRenderer that can only render
|
||||
// a checkerboard pattern.
|
||||
@ -224,13 +224,13 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
_framebuffer_size: api::DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
) {
|
||||
let blob_img1 = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img1,
|
||||
api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true, false),
|
||||
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 50, 150, 255))),
|
||||
@ -238,7 +238,7 @@ impl Example for App {
|
||||
);
|
||||
|
||||
let blob_img2 = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img2,
|
||||
api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true, false),
|
||||
api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 150, 50, 255))),
|
||||
|
@ -71,7 +71,7 @@ pub trait Example {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
framebuffer_size: DeviceUintSize,
|
||||
pipeline_id: PipelineId,
|
||||
document_id: DocumentId,
|
||||
@ -169,17 +169,16 @@ pub fn main_wrapper<E: Example>(
|
||||
let pipeline_id = PipelineId(0, 0);
|
||||
let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
|
||||
let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
example.render(
|
||||
&api,
|
||||
&mut builder,
|
||||
&mut resources,
|
||||
&mut txn,
|
||||
framebuffer_size,
|
||||
pipeline_id,
|
||||
document_id,
|
||||
);
|
||||
let mut txn = Transaction::new();
|
||||
txn.set_display_list(
|
||||
epoch,
|
||||
None,
|
||||
@ -187,7 +186,6 @@ pub fn main_wrapper<E: Example>(
|
||||
builder.finalize(),
|
||||
true,
|
||||
);
|
||||
txn.update_resources(resources);
|
||||
txn.set_root_pipeline(pipeline_id);
|
||||
txn.generate_frame();
|
||||
api.send_transaction(document_id, txn);
|
||||
@ -251,12 +249,11 @@ pub fn main_wrapper<E: Example>(
|
||||
|
||||
if custom_event {
|
||||
let mut builder = DisplayListBuilder::new(pipeline_id, layout_size);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
|
||||
example.render(
|
||||
&api,
|
||||
&mut builder,
|
||||
&mut resources,
|
||||
&mut txn,
|
||||
framebuffer_size,
|
||||
pipeline_id,
|
||||
document_id,
|
||||
@ -268,7 +265,6 @@ pub fn main_wrapper<E: Example>(
|
||||
builder.finalize(),
|
||||
true,
|
||||
);
|
||||
txn.update_resources(resources);
|
||||
txn.generate_frame();
|
||||
}
|
||||
api.send_transaction(document_id, txn);
|
||||
|
@ -87,7 +87,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
base_builder: &mut DisplayListBuilder,
|
||||
_: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
framebuffer_size: DeviceUintSize,
|
||||
_: PipelineId,
|
||||
_: DocumentId,
|
||||
|
@ -67,8 +67,8 @@ impl App {
|
||||
) {
|
||||
// Generate the external image key that will be used to render the output document to the root document.
|
||||
self.external_image_key = Some(api.generate_image_key());
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.add_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.add_image(
|
||||
self.external_image_key.unwrap(),
|
||||
ImageDescriptor::new(100, 100, ImageFormat::BGRA8, true, false),
|
||||
ImageData::External(ExternalImageData {
|
||||
@ -112,10 +112,8 @@ impl App {
|
||||
builder.push_rect(&info, ColorF::new(1.0, 1.0, 0.0, 1.0));
|
||||
builder.pop_stacking_context();
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
txn.set_root_pipeline(pipeline_id);
|
||||
txn.enable_frame_output(document.pipeline_id, true);
|
||||
txn.update_resources(resources);
|
||||
txn.set_display_list(
|
||||
Epoch(0),
|
||||
Some(document.color),
|
||||
@ -134,7 +132,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_resources: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
|
@ -23,7 +23,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_resources: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
pipeline_id: PipelineId,
|
||||
document_id: DocumentId,
|
||||
|
@ -23,13 +23,13 @@ impl Example for App {
|
||||
&mut self,
|
||||
_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
) {
|
||||
let (image_descriptor, image_data) = image_helper::make_checkerboard(32, 32);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
self.image_key,
|
||||
image_descriptor,
|
||||
image_data,
|
||||
@ -99,15 +99,14 @@ impl Example for App {
|
||||
}
|
||||
}
|
||||
|
||||
let mut updates = ResourceUpdates::new();
|
||||
updates.update_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_image(
|
||||
self.image_key,
|
||||
ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(image_data),
|
||||
None,
|
||||
);
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_resources(updates);
|
||||
txn.generate_frame();
|
||||
api.send_transaction(document_id, txn);
|
||||
}
|
||||
|
@ -102,17 +102,15 @@ impl Window {
|
||||
|
||||
let epoch = Epoch(0);
|
||||
let pipeline_id = PipelineId(0, 0);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
let font_key = api.generate_font_key();
|
||||
let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
|
||||
resources.add_raw_font(font_key, font_bytes, 0);
|
||||
txn.add_raw_font(font_key, font_bytes, 0);
|
||||
|
||||
let font_instance_key = api.generate_font_instance_key();
|
||||
resources.add_font_instance(font_instance_key, font_key, Au::from_px(32), None, None, Vec::new());
|
||||
txn.add_font_instance(font_instance_key, font_key, Au::from_px(32), None, None, Vec::new());
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_resources(resources);
|
||||
api.send_transaction(document_id, txn);
|
||||
|
||||
Window {
|
||||
|
@ -23,7 +23,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
_api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
_resources: &mut ResourceUpdates,
|
||||
_txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
|
@ -83,7 +83,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
@ -110,7 +110,7 @@ impl Example for App {
|
||||
let key1 = api.generate_image_key();
|
||||
|
||||
self.image_generator.generate_image(128);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
key0,
|
||||
ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(self.image_generator.take()),
|
||||
@ -118,7 +118,7 @@ impl Example for App {
|
||||
);
|
||||
|
||||
self.image_generator.generate_image(128);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
key1,
|
||||
ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(self.image_generator.take()),
|
||||
@ -200,7 +200,7 @@ impl Example for App {
|
||||
},
|
||||
..
|
||||
} => {
|
||||
let mut updates = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
match key {
|
||||
glutin::VirtualKeyCode::S => {
|
||||
@ -214,7 +214,7 @@ impl Example for App {
|
||||
|
||||
self.image_generator.generate_image(size);
|
||||
|
||||
updates.add_image(
|
||||
txn.add_image(
|
||||
image_key,
|
||||
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(self.image_generator.take()),
|
||||
@ -226,13 +226,13 @@ impl Example for App {
|
||||
}
|
||||
}
|
||||
glutin::VirtualKeyCode::D => if let Some(image_key) = self.image_key.take() {
|
||||
updates.delete_image(image_key);
|
||||
txn.delete_image(image_key);
|
||||
},
|
||||
glutin::VirtualKeyCode::U => if let Some(image_key) = self.image_key {
|
||||
let size = 128;
|
||||
self.image_generator.generate_image(size);
|
||||
|
||||
updates.update_image(
|
||||
txn.update_image(
|
||||
image_key,
|
||||
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(self.image_generator.take()),
|
||||
@ -241,7 +241,7 @@ impl Example for App {
|
||||
},
|
||||
glutin::VirtualKeyCode::E => {
|
||||
if let Some(image_key) = self.image_key.take() {
|
||||
updates.delete_image(image_key);
|
||||
txn.delete_image(image_key);
|
||||
}
|
||||
|
||||
let size = 32;
|
||||
@ -253,7 +253,7 @@ impl Example for App {
|
||||
image_type: ExternalImageType::Buffer,
|
||||
};
|
||||
|
||||
updates.add_image(
|
||||
txn.add_image(
|
||||
image_key,
|
||||
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
|
||||
ImageData::External(image_data),
|
||||
@ -264,14 +264,14 @@ impl Example for App {
|
||||
}
|
||||
glutin::VirtualKeyCode::R => {
|
||||
if let Some(image_key) = self.image_key.take() {
|
||||
updates.delete_image(image_key);
|
||||
txn.delete_image(image_key);
|
||||
}
|
||||
|
||||
let image_key = api.generate_image_key();
|
||||
let size = 32;
|
||||
self.image_generator.generate_image(size);
|
||||
|
||||
updates.add_image(
|
||||
txn.add_image(
|
||||
image_key,
|
||||
ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(self.image_generator.take()),
|
||||
@ -283,7 +283,7 @@ impl Example for App {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
api.update_resources(updates);
|
||||
api.update_resources(txn.resource_updates);
|
||||
return true;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -78,7 +78,7 @@ impl Example for App {
|
||||
&mut self,
|
||||
api: &RenderApi,
|
||||
builder: &mut DisplayListBuilder,
|
||||
resources: &mut ResourceUpdates,
|
||||
txn: &mut Transaction,
|
||||
_framebuffer_size: DeviceUintSize,
|
||||
_pipeline_id: PipelineId,
|
||||
_document_id: DocumentId,
|
||||
@ -100,7 +100,7 @@ impl Example for App {
|
||||
let yuv_chanel2 = api.generate_image_key();
|
||||
let yuv_chanel2_1 = api.generate_image_key();
|
||||
let yuv_chanel3 = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
yuv_chanel1,
|
||||
ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
|
||||
ImageData::External(ExternalImageData {
|
||||
@ -112,7 +112,7 @@ impl Example for App {
|
||||
}),
|
||||
None,
|
||||
);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
yuv_chanel2,
|
||||
ImageDescriptor::new(100, 100, ImageFormat::RG8, true, false),
|
||||
ImageData::External(ExternalImageData {
|
||||
@ -124,7 +124,7 @@ impl Example for App {
|
||||
}),
|
||||
None,
|
||||
);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
yuv_chanel2_1,
|
||||
ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
|
||||
ImageData::External(ExternalImageData {
|
||||
@ -136,7 +136,7 @@ impl Example for App {
|
||||
}),
|
||||
None,
|
||||
);
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
yuv_chanel3,
|
||||
ImageDescriptor::new(100, 100, ImageFormat::R8, true, false),
|
||||
ImageData::External(ExternalImageData {
|
||||
|
@ -48,7 +48,7 @@ vec2 transform_point_snapped(
|
||||
RectWithSize local_rect,
|
||||
mat4 transform
|
||||
) {
|
||||
vec2 snap_offset = compute_snap_offset(local_pos, transform, local_rect);
|
||||
vec2 snap_offset = compute_snap_offset(local_pos, transform, local_rect, vec2(0.5));
|
||||
vec4 world_pos = transform * vec4(local_pos, 0.0, 1.0);
|
||||
vec2 device_pos = world_pos.xy / world_pos.w * uDevicePixelRatio;
|
||||
|
||||
|
@ -67,7 +67,8 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
|
||||
scroll_node.transform,
|
||||
local_clip_rect,
|
||||
RectWithSize(snap_positions.xy, snap_positions.zw - snap_positions.xy),
|
||||
snap_positions
|
||||
snap_positions,
|
||||
vec2(0.5)
|
||||
);
|
||||
|
||||
actual_pos -= snap_offsets;
|
||||
|
127
gfx/webrender/res/cs_border_segment.glsl
Normal file
127
gfx/webrender/res/cs_border_segment.glsl
Normal file
@ -0,0 +1,127 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include shared,prim_shared,ellipse,shared_border
|
||||
|
||||
flat varying vec4 vColor0;
|
||||
flat varying vec4 vColor1;
|
||||
flat varying vec4 vColorLine;
|
||||
flat varying int vFeatures;
|
||||
flat varying vec2 vClipCenter;
|
||||
flat varying vec4 vClipRadii;
|
||||
flat varying vec2 vClipSign;
|
||||
|
||||
varying vec2 vPos;
|
||||
|
||||
#define CLIP_RADII 1
|
||||
#define MIX_COLOR 2
|
||||
|
||||
#ifdef WR_VERTEX_SHADER
|
||||
|
||||
in vec2 aTaskOrigin;
|
||||
in vec4 aRect;
|
||||
in vec4 aColor0;
|
||||
in vec4 aColor1;
|
||||
in int aFlags;
|
||||
in vec2 aWidths;
|
||||
in vec2 aRadii;
|
||||
|
||||
#define SEGMENT_TOP_LEFT 0
|
||||
#define SEGMENT_TOP_RIGHT 1
|
||||
#define SEGMENT_BOTTOM_RIGHT 2
|
||||
#define SEGMENT_BOTTOM_LEFT 3
|
||||
#define SEGMENT_LEFT 4
|
||||
#define SEGMENT_TOP 5
|
||||
#define SEGMENT_RIGHT 6
|
||||
#define SEGMENT_BOTTOM 7
|
||||
|
||||
vec2 get_outer_corner_scale(int segment) {
|
||||
vec2 p;
|
||||
|
||||
switch (segment) {
|
||||
case SEGMENT_TOP_LEFT:
|
||||
p = vec2(0.0, 0.0);
|
||||
break;
|
||||
case SEGMENT_TOP_RIGHT:
|
||||
p = vec2(1.0, 0.0);
|
||||
break;
|
||||
case SEGMENT_BOTTOM_RIGHT:
|
||||
p = vec2(1.0, 1.0);
|
||||
break;
|
||||
case SEGMENT_BOTTOM_LEFT:
|
||||
p = vec2(0.0, 1.0);
|
||||
break;
|
||||
default:
|
||||
// Should never get hit
|
||||
p = vec2(0.0);
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void main(void) {
|
||||
vec2 pos = aRect.xy + aRect.zw * aPosition.xy;
|
||||
|
||||
int segment = aFlags & 0xff;
|
||||
int style = (aFlags >> 8) & 0xff;
|
||||
|
||||
vec2 outer_scale = get_outer_corner_scale(segment);
|
||||
vec2 outer = aRect.xy + outer_scale * aRect.zw;
|
||||
vec2 clip_sign = 1.0 - 2.0 * outer_scale;
|
||||
|
||||
vColor0 = aColor0;
|
||||
vColor1 = aColor1;
|
||||
vPos = pos;
|
||||
|
||||
vFeatures = 0;
|
||||
vClipSign = clip_sign;
|
||||
vClipCenter = outer + clip_sign * aRadii;
|
||||
vClipRadii = vec4(aRadii, aRadii - aWidths);
|
||||
vColorLine = vec4(0.0);
|
||||
|
||||
switch (segment) {
|
||||
case SEGMENT_TOP_LEFT:
|
||||
case SEGMENT_TOP_RIGHT:
|
||||
case SEGMENT_BOTTOM_RIGHT:
|
||||
case SEGMENT_BOTTOM_LEFT:
|
||||
vFeatures |= (CLIP_RADII | MIX_COLOR);
|
||||
vColorLine = vec4(outer, aWidths.y * -clip_sign.y, aWidths.x * clip_sign.x);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gl_Position = uTransform * vec4(aTaskOrigin + pos, 0.0, 1.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
void main(void) {
|
||||
float aa_range = compute_aa_range(vPos);
|
||||
float d = -1.0;
|
||||
|
||||
// Apply color mix
|
||||
float mix_factor = 0.0;
|
||||
if ((vFeatures & MIX_COLOR) != 0) {
|
||||
float d_line = distance_to_line(vColorLine.xy, vColorLine.zw, vPos);
|
||||
mix_factor = distance_aa(aa_range, -d_line);
|
||||
}
|
||||
|
||||
// Apply clip radii
|
||||
if ((vFeatures & CLIP_RADII) != 0) {
|
||||
vec2 p = vPos - vClipCenter;
|
||||
if (vClipSign.x * p.x < 0.0 && vClipSign.y * p.y < 0.0) {
|
||||
float d_radii_a = distance_to_ellipse(p, vClipRadii.xy, aa_range);
|
||||
float d_radii_b = distance_to_ellipse(p, vClipRadii.zw, aa_range);
|
||||
float d_radii = max(d_radii_a, -d_radii_b);
|
||||
d = max(d, d_radii);
|
||||
}
|
||||
}
|
||||
|
||||
float alpha = distance_aa(aa_range, d);
|
||||
vec4 color = mix(vColor0, vColor1, mix_factor);
|
||||
oFragColor = color * alpha;
|
||||
}
|
||||
#endif
|
@ -10,6 +10,7 @@
|
||||
#define SUBPX_DIR_NONE 0
|
||||
#define SUBPX_DIR_HORIZONTAL 1
|
||||
#define SUBPX_DIR_VERTICAL 2
|
||||
#define SUBPX_DIR_MIXED 3
|
||||
|
||||
#define RASTER_LOCAL 0
|
||||
#define RASTER_SCREEN 1
|
||||
@ -68,8 +69,7 @@ struct Glyph {
|
||||
};
|
||||
|
||||
Glyph fetch_glyph(int specific_prim_address,
|
||||
int glyph_index,
|
||||
int subpx_dir) {
|
||||
int glyph_index) {
|
||||
// Two glyphs are packed in each texel in the GPU cache.
|
||||
int glyph_address = specific_prim_address +
|
||||
VECS_PER_TEXT_RUN +
|
||||
@ -80,24 +80,6 @@ Glyph fetch_glyph(int specific_prim_address,
|
||||
// bug with equality comparisons on integers.
|
||||
vec2 glyph = mix(data.xy, data.zw, bvec2(glyph_index % 2 != 0));
|
||||
|
||||
// In subpixel mode, the subpixel offset has already been
|
||||
// accounted for while rasterizing the glyph.
|
||||
switch (subpx_dir) {
|
||||
case SUBPX_DIR_NONE:
|
||||
break;
|
||||
case SUBPX_DIR_HORIZONTAL:
|
||||
// Glyphs positioned [-0.125, 0.125] get a
|
||||
// subpx position of zero. So include that
|
||||
// offset in the glyph position to ensure
|
||||
// we round to the correct whole position.
|
||||
glyph.x = floor(glyph.x + 0.125);
|
||||
break;
|
||||
case SUBPX_DIR_VERTICAL:
|
||||
glyph.y = floor(glyph.y + 0.125);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return Glyph(glyph);
|
||||
}
|
||||
|
||||
@ -231,7 +213,8 @@ VertexInfo write_vertex(RectWithSize instance_rect,
|
||||
vec2 snap_offset = compute_snap_offset(
|
||||
clamped_local_pos,
|
||||
scroll_node.transform,
|
||||
snap_rect
|
||||
snap_rect,
|
||||
vec2(0.5)
|
||||
);
|
||||
|
||||
// Transform the current vertex to world space.
|
||||
|
@ -20,7 +20,14 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||
float z,
|
||||
ClipScrollNode scroll_node,
|
||||
PictureTask task,
|
||||
RectWithSize snap_rect) {
|
||||
RectWithSize snap_rect,
|
||||
vec2 snap_bias) {
|
||||
#if defined(WR_FEATURE_GLYPH_TRANSFORM) || !defined(WR_FEATURE_TRANSFORM)
|
||||
// Ensure the transform does not contain a subpixel translation to ensure
|
||||
// that glyph snapping is stable for equivalent glyph subpixel positions.
|
||||
scroll_node.transform[3].xy = floor(scroll_node.transform[3].xy + 0.5);
|
||||
#endif
|
||||
|
||||
// Transform the current vertex to world space.
|
||||
vec4 world_pos = scroll_node.transform * vec4(clamped_local_pos, 0.0, 1.0);
|
||||
|
||||
@ -34,15 +41,14 @@ VertexInfo write_text_vertex(vec2 clamped_local_pos,
|
||||
|
||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||
// For transformed subpixels, we just need to align the glyph origin to a device pixel.
|
||||
// Only check the scroll node transform's translation since the scales and axes match.
|
||||
vec2 world_snap_p0 = snap_rect.p0 + scroll_node.transform[3].xy * uDevicePixelRatio;
|
||||
final_pos += floor(world_snap_p0 + 0.5) - world_snap_p0;
|
||||
final_pos += floor(snap_rect.p0 + snap_bias) - snap_rect.p0;
|
||||
#elif !defined(WR_FEATURE_TRANSFORM)
|
||||
// Compute the snapping offset only if the scroll node transform is axis-aligned.
|
||||
final_pos += compute_snap_offset(
|
||||
clamped_local_pos,
|
||||
scroll_node.transform,
|
||||
snap_rect
|
||||
snap_rect,
|
||||
snap_bias
|
||||
);
|
||||
#endif
|
||||
|
||||
@ -71,9 +77,7 @@ void main(void) {
|
||||
color_mode = uMode;
|
||||
}
|
||||
|
||||
Glyph glyph = fetch_glyph(prim.specific_prim_address,
|
||||
glyph_index,
|
||||
subpx_dir);
|
||||
Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index);
|
||||
GlyphResource res = fetch_glyph_resource(resource_address);
|
||||
|
||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||
@ -112,12 +116,38 @@ void main(void) {
|
||||
local_pos = clamp_rect(local_pos, prim.local_clip_rect);
|
||||
#endif
|
||||
|
||||
vec2 snap_bias;
|
||||
// In subpixel mode, the subpixel offset has already been
|
||||
// accounted for while rasterizing the glyph. However, we
|
||||
// must still round with a subpixel bias rather than rounding
|
||||
// to the nearest whole pixel, depending on subpixel direciton.
|
||||
switch (subpx_dir) {
|
||||
case SUBPX_DIR_NONE:
|
||||
default:
|
||||
snap_bias = vec2(0.5);
|
||||
break;
|
||||
case SUBPX_DIR_HORIZONTAL:
|
||||
// Glyphs positioned [-0.125, 0.125] get a
|
||||
// subpx position of zero. So include that
|
||||
// offset in the glyph position to ensure
|
||||
// we round to the correct whole position.
|
||||
snap_bias = vec2(0.125, 0.5);
|
||||
break;
|
||||
case SUBPX_DIR_VERTICAL:
|
||||
snap_bias = vec2(0.5, 0.125);
|
||||
break;
|
||||
case SUBPX_DIR_MIXED:
|
||||
snap_bias = vec2(0.125);
|
||||
break;
|
||||
}
|
||||
|
||||
VertexInfo vi = write_text_vertex(local_pos,
|
||||
prim.local_clip_rect,
|
||||
prim.z,
|
||||
prim.scroll_node,
|
||||
prim.task,
|
||||
glyph_rect);
|
||||
glyph_rect,
|
||||
snap_bias);
|
||||
|
||||
#ifdef WR_FEATURE_GLYPH_TRANSFORM
|
||||
vec2 f = (transform * vi.local_pos - glyph_rect.p0) / glyph_rect.size;
|
||||
|
@ -27,10 +27,11 @@ vec2 compute_snap_offset_impl(
|
||||
mat4 transform,
|
||||
RectWithSize snap_rect,
|
||||
RectWithSize reference_rect,
|
||||
vec4 snap_positions) {
|
||||
vec4 snap_positions,
|
||||
vec2 snap_bias) {
|
||||
|
||||
/// World offsets applied to the corners of the snap rectangle.
|
||||
vec4 snap_offsets = floor(snap_positions + 0.5) - snap_positions;
|
||||
vec4 snap_offsets = floor(snap_positions + snap_bias.xyxy) - snap_positions;
|
||||
|
||||
/// Compute the position of this vertex inside the snap rectangle.
|
||||
vec2 normalized_snap_pos = (reference_pos - reference_rect.p0) / reference_rect.size;
|
||||
@ -43,7 +44,8 @@ vec2 compute_snap_offset_impl(
|
||||
// given local position on the scroll_node and a snap rectangle.
|
||||
vec2 compute_snap_offset(vec2 local_pos,
|
||||
mat4 transform,
|
||||
RectWithSize snap_rect) {
|
||||
RectWithSize snap_rect,
|
||||
vec2 snap_bias) {
|
||||
vec4 snap_positions = compute_snap_positions(
|
||||
transform,
|
||||
snap_rect
|
||||
@ -54,7 +56,8 @@ vec2 compute_snap_offset(vec2 local_pos,
|
||||
transform,
|
||||
snap_rect,
|
||||
snap_rect,
|
||||
snap_positions
|
||||
snap_positions,
|
||||
snap_bias
|
||||
);
|
||||
|
||||
return snap_offsets;
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
use api::{AlphaType, ClipMode, DeviceIntRect, DeviceIntSize};
|
||||
use api::{DeviceUintRect, DeviceUintPoint, ExternalImageType, FilterOp, ImageRendering, LayoutRect};
|
||||
use api::{DeviceIntPoint, SubpixelDirection, YuvColorSpace, YuvFormat};
|
||||
use api::{DeviceIntPoint, YuvColorSpace, YuvFormat};
|
||||
use api::{LayoutToWorldTransform, WorldPixel};
|
||||
use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind};
|
||||
use clip::{ClipSource, ClipStore, ClipWorkItem};
|
||||
@ -22,7 +22,7 @@ use plane_split::{BspSplitter, Polygon, Splitter};
|
||||
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentTaskId, CachedGradient, DeferredResolve};
|
||||
use prim_store::{EdgeAaSegmentMask, ImageSource, PictureIndex, PrimitiveIndex, PrimitiveKind};
|
||||
use prim_store::{PrimitiveMetadata, PrimitiveRun, PrimitiveStore, VisibleGradientTile};
|
||||
use prim_store::CachedGradientIndex;
|
||||
use prim_store::{BorderSource, CachedGradientIndex};
|
||||
use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree};
|
||||
use renderer::{BlendMode, ImageBufferKind};
|
||||
use renderer::{BLOCKS_PER_UV_RECT, ShaderColorMode};
|
||||
@ -1153,6 +1153,7 @@ impl AlphaBatchBuilder {
|
||||
ctx.device_pixel_scale,
|
||||
Some(scroll_node.transform),
|
||||
);
|
||||
let subpx_dir = font.get_subpx_dir();
|
||||
|
||||
let glyph_fetch_buffer = &mut self.glyph_fetch_buffer;
|
||||
let batch_list = &mut self.batch_list;
|
||||
@ -1170,11 +1171,7 @@ impl AlphaBatchBuilder {
|
||||
glyph_format = glyph_format.ignore_color();
|
||||
}
|
||||
|
||||
let subpx_dir = match glyph_format {
|
||||
GlyphFormat::Bitmap |
|
||||
GlyphFormat::ColorBitmap => SubpixelDirection::None,
|
||||
_ => text_cpu.font.subpx_dir.limit_by(text_cpu.font.render_mode),
|
||||
};
|
||||
let subpx_dir = subpx_dir.limit_by(glyph_format);
|
||||
|
||||
let textures = BatchTextures {
|
||||
colors: [
|
||||
@ -1524,13 +1521,25 @@ impl BrushPrimitive {
|
||||
))
|
||||
}
|
||||
}
|
||||
BrushKind::Border { request, .. } => {
|
||||
let cache_item = resolve_image(
|
||||
request,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
deferred_resolves,
|
||||
);
|
||||
BrushKind::Border { ref source, .. } => {
|
||||
let cache_item = match *source {
|
||||
BorderSource::Image(request) => {
|
||||
resolve_image(
|
||||
request,
|
||||
resource_cache,
|
||||
gpu_cache,
|
||||
deferred_resolves,
|
||||
)
|
||||
}
|
||||
BorderSource::Border { ref handle, .. } => {
|
||||
let rt_handle = handle
|
||||
.as_ref()
|
||||
.expect("bug: render task handle not allocated");
|
||||
let rt_cache_entry = resource_cache
|
||||
.get_cached_render_task(rt_handle);
|
||||
resource_cache.get_texture_cache_item(&rt_cache_entry.handle)
|
||||
}
|
||||
};
|
||||
|
||||
if cache_item.texture_id == SourceTexture::Invalid {
|
||||
None
|
||||
|
@ -2,16 +2,18 @@
|
||||
* 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 api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ClipMode, ColorF, LayoutPoint};
|
||||
use api::{LayoutPrimitiveInfo, LayoutRect, LayoutSize, NormalBorder};
|
||||
use api::{BorderRadius, BorderSide, BorderStyle, BorderWidths, ColorF, LayoutPoint};
|
||||
use api::{ColorU, DeviceRect, DeviceSize, LayoutSizeAu, LayoutPrimitiveInfo, LayoutToDeviceScale};
|
||||
use api::{DevicePoint, DeviceIntSize, LayoutRect, LayoutSize, NormalBorder};
|
||||
use app_units::Au;
|
||||
use clip::ClipSource;
|
||||
use ellipse::Ellipse;
|
||||
use display_list_flattener::DisplayListFlattener;
|
||||
use gpu_types::BrushFlags;
|
||||
use gpu_types::{BorderInstance, BorderSegment, BrushFlags};
|
||||
use gpu_cache::GpuDataRequest;
|
||||
use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushSegment, BrushSegmentDescriptor};
|
||||
use prim_store::{EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
|
||||
use util::{lerp, pack_as_float};
|
||||
use prim_store::{BorderPrimitiveCpu, BrushClipMaskKind, BrushKind, BrushPrimitive, BrushSegment, BrushSegmentDescriptor};
|
||||
use prim_store::{BorderSource, EdgeAaSegmentMask, PrimitiveContainer, ScrollNodeAndClipChain};
|
||||
use util::{lerp, pack_as_float, RectHelpers};
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
@ -36,6 +38,96 @@ enum BorderCorner {
|
||||
BottomRight,
|
||||
}
|
||||
|
||||
trait AuSizeConverter {
|
||||
fn to_au(&self) -> LayoutSizeAu;
|
||||
}
|
||||
|
||||
impl AuSizeConverter for LayoutSize {
|
||||
fn to_au(&self) -> LayoutSizeAu {
|
||||
LayoutSizeAu::new(
|
||||
Au::from_f32_px(self.width),
|
||||
Au::from_f32_px(self.height),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(gw): Perhaps there is a better way to store
|
||||
// the border cache key than duplicating
|
||||
// all the border structs with hashable
|
||||
// variants...
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderRadiusAu {
|
||||
pub top_left: LayoutSizeAu,
|
||||
pub top_right: LayoutSizeAu,
|
||||
pub bottom_left: LayoutSizeAu,
|
||||
pub bottom_right: LayoutSizeAu,
|
||||
}
|
||||
|
||||
impl From<BorderRadius> for BorderRadiusAu {
|
||||
fn from(radius: BorderRadius) -> BorderRadiusAu {
|
||||
BorderRadiusAu {
|
||||
top_left: radius.top_left.to_au(),
|
||||
top_right: radius.top_right.to_au(),
|
||||
bottom_right: radius.bottom_right.to_au(),
|
||||
bottom_left: radius.bottom_left.to_au(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderWidthsAu {
|
||||
pub left: Au,
|
||||
pub top: Au,
|
||||
pub right: Au,
|
||||
pub bottom: Au,
|
||||
}
|
||||
|
||||
impl From<BorderWidths> for BorderWidthsAu {
|
||||
fn from(widths: BorderWidths) -> Self {
|
||||
BorderWidthsAu {
|
||||
left: Au::from_f32_px(widths.left),
|
||||
top: Au::from_f32_px(widths.top),
|
||||
right: Au::from_f32_px(widths.right),
|
||||
bottom: Au::from_f32_px(widths.bottom),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderSideAu {
|
||||
pub color: ColorU,
|
||||
pub style: BorderStyle,
|
||||
}
|
||||
|
||||
impl From<BorderSide> for BorderSideAu {
|
||||
fn from(side: BorderSide) -> Self {
|
||||
BorderSideAu {
|
||||
color: side.color.into(),
|
||||
style: side.style,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderCacheKey {
|
||||
pub left: BorderSideAu,
|
||||
pub right: BorderSideAu,
|
||||
pub top: BorderSideAu,
|
||||
pub bottom: BorderSideAu,
|
||||
pub radius: BorderRadiusAu,
|
||||
pub widths: BorderWidthsAu,
|
||||
pub scale: Au,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum BorderCornerKind {
|
||||
None,
|
||||
@ -374,60 +466,54 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
let top = &border.top;
|
||||
let bottom = &border.bottom;
|
||||
|
||||
let constant_color = left.color;
|
||||
let is_simple_border = [left, top, right, bottom].iter().all(|edge| {
|
||||
edge.style == BorderStyle::Solid &&
|
||||
edge.color == constant_color
|
||||
let brush_border_supported = [left, top, right, bottom].iter().all(|edge| {
|
||||
match edge.style {
|
||||
BorderStyle::Solid |
|
||||
BorderStyle::Hidden |
|
||||
BorderStyle::None |
|
||||
BorderStyle::Inset |
|
||||
BorderStyle::Outset => {
|
||||
true
|
||||
}
|
||||
|
||||
BorderStyle::Double |
|
||||
BorderStyle::Dotted |
|
||||
BorderStyle::Dashed |
|
||||
BorderStyle::Groove |
|
||||
BorderStyle::Ridge => {
|
||||
false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if is_simple_border {
|
||||
let extra_clips = vec![
|
||||
ClipSource::new_rounded_rect(
|
||||
info.rect,
|
||||
border.radius,
|
||||
ClipMode::Clip,
|
||||
),
|
||||
ClipSource::new_rounded_rect(
|
||||
LayoutRect::new(
|
||||
LayoutPoint::new(
|
||||
info.rect.origin.x + widths.left,
|
||||
info.rect.origin.y + widths.top,
|
||||
),
|
||||
LayoutSize::new(
|
||||
info.rect.size.width - widths.left - widths.right,
|
||||
info.rect.size.height - widths.top - widths.bottom,
|
||||
),
|
||||
),
|
||||
BorderRadius {
|
||||
top_left: LayoutSize::new(
|
||||
(border.radius.top_left.width - widths.left).max(0.0),
|
||||
(border.radius.top_left.height - widths.top).max(0.0),
|
||||
),
|
||||
top_right: LayoutSize::new(
|
||||
(border.radius.top_right.width - widths.right).max(0.0),
|
||||
(border.radius.top_right.height - widths.top).max(0.0),
|
||||
),
|
||||
bottom_left: LayoutSize::new(
|
||||
(border.radius.bottom_left.width - widths.left).max(0.0),
|
||||
(border.radius.bottom_left.height - widths.bottom).max(0.0),
|
||||
),
|
||||
bottom_right: LayoutSize::new(
|
||||
(border.radius.bottom_right.width - widths.right).max(0.0),
|
||||
(border.radius.bottom_right.height - widths.bottom).max(0.0),
|
||||
),
|
||||
if brush_border_supported {
|
||||
let prim = BrushPrimitive::new(
|
||||
BrushKind::Border {
|
||||
source: BorderSource::Border {
|
||||
border,
|
||||
widths: *widths,
|
||||
cache_key: BorderCacheKey {
|
||||
left: border.left.into(),
|
||||
top: border.top.into(),
|
||||
right: border.right.into(),
|
||||
bottom: border.bottom.into(),
|
||||
widths: (*widths).into(),
|
||||
radius: border.radius.into(),
|
||||
scale: Au::from_f32_px(0.0),
|
||||
},
|
||||
task_info: None,
|
||||
handle: None,
|
||||
},
|
||||
ClipMode::ClipOut,
|
||||
),
|
||||
];
|
||||
|
||||
self.add_solid_rectangle(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
border.top.color,
|
||||
},
|
||||
None,
|
||||
extra_clips,
|
||||
);
|
||||
|
||||
self.add_primitive(
|
||||
clip_and_scroll,
|
||||
info,
|
||||
Vec::new(),
|
||||
PrimitiveContainer::Brush(prim),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -505,8 +591,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
let p3 = info.rect.bottom_right();
|
||||
|
||||
let segment = |x0, y0, x1, y1| BrushSegment::new(
|
||||
LayoutPoint::new(x0, y0),
|
||||
LayoutSize::new(x1-x0, y1-y0),
|
||||
LayoutRect::from_floats(x0, y0, x1, y1),
|
||||
true,
|
||||
EdgeAaSegmentMask::all(), // Note: this doesn't seem right, needs revision
|
||||
[0.0; 4],
|
||||
@ -929,3 +1014,434 @@ impl DotInfo {
|
||||
DotInfo { arc_pos, diameter }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BorderRenderTaskInfo {
|
||||
pub instances: Vec<BorderInstance>,
|
||||
pub segments: Vec<BrushSegment>,
|
||||
pub size: DeviceIntSize,
|
||||
}
|
||||
|
||||
impl BorderRenderTaskInfo {
|
||||
pub fn new(
|
||||
rect: &LayoutRect,
|
||||
border: &NormalBorder,
|
||||
widths: &BorderWidths,
|
||||
scale: LayoutToDeviceScale,
|
||||
) -> Self {
|
||||
let mut instances = Vec::new();
|
||||
let mut segments = Vec::new();
|
||||
|
||||
let dp_width_top = (widths.top * scale.0).ceil();
|
||||
let dp_width_bottom = (widths.bottom * scale.0).ceil();
|
||||
let dp_width_left = (widths.left * scale.0).ceil();
|
||||
let dp_width_right = (widths.right * scale.0).ceil();
|
||||
|
||||
let dp_corner_tl = (border.radius.top_left * scale).ceil();
|
||||
let dp_corner_tr = (border.radius.top_right * scale).ceil();
|
||||
let dp_corner_bl = (border.radius.bottom_left * scale).ceil();
|
||||
let dp_corner_br = (border.radius.bottom_right * scale).ceil();
|
||||
|
||||
let dp_size_tl = DeviceSize::new(
|
||||
dp_corner_tl.width.max(dp_width_left),
|
||||
dp_corner_tl.height.max(dp_width_top),
|
||||
);
|
||||
let dp_size_tr = DeviceSize::new(
|
||||
dp_corner_tr.width.max(dp_width_right),
|
||||
dp_corner_tr.height.max(dp_width_top),
|
||||
);
|
||||
let dp_size_br = DeviceSize::new(
|
||||
dp_corner_br.width.max(dp_width_right),
|
||||
dp_corner_br.height.max(dp_width_bottom),
|
||||
);
|
||||
let dp_size_bl = DeviceSize::new(
|
||||
dp_corner_bl.width.max(dp_width_left),
|
||||
dp_corner_bl.height.max(dp_width_bottom),
|
||||
);
|
||||
|
||||
let local_size_tl = LayoutSize::new(
|
||||
border.radius.top_left.width.max(widths.left),
|
||||
border.radius.top_left.height.max(widths.top),
|
||||
);
|
||||
let local_size_tr = LayoutSize::new(
|
||||
border.radius.top_right.width.max(widths.right),
|
||||
border.radius.top_right.height.max(widths.top),
|
||||
);
|
||||
let local_size_br = LayoutSize::new(
|
||||
border.radius.bottom_right.width.max(widths.right),
|
||||
border.radius.bottom_right.height.max(widths.bottom),
|
||||
);
|
||||
let local_size_bl = LayoutSize::new(
|
||||
border.radius.bottom_left.width.max(widths.left),
|
||||
border.radius.bottom_left.height.max(widths.bottom),
|
||||
);
|
||||
|
||||
// TODO(gw): The inner and outer widths don't matter for simple
|
||||
// border types. Once we push dashing and dotted styles
|
||||
// through border brushes, we need to calculate an
|
||||
// appropriate length here.
|
||||
let width_inner = 16.0;
|
||||
let height_inner = 16.0;
|
||||
|
||||
let size = DeviceSize::new(
|
||||
dp_size_tl.width.max(dp_size_bl.width) + width_inner + dp_size_tr.width.max(dp_size_br.width),
|
||||
dp_size_tl.height.max(dp_size_tr.height) + height_inner + dp_size_bl.height.max(dp_size_br.height),
|
||||
);
|
||||
|
||||
// These modulate colors are not part of the specification. They
|
||||
// are derived from the Gecko source code and experimentation, and
|
||||
// used to modulate the colors in order to generate colors for
|
||||
// the inset/outset and groove/ridge border styles.
|
||||
let left_color = border.left.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
|
||||
let top_color = border.top.border_color(1.0, 2.0 / 3.0, 0.3, 0.7);
|
||||
let right_color = border.right.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
|
||||
let bottom_color = border.bottom.border_color(2.0 / 3.0, 1.0, 0.7, 0.3);
|
||||
|
||||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y + local_size_tl.height,
|
||||
rect.origin.x + widths.left,
|
||||
rect.origin.y + rect.size.height - local_size_bl.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
0.0,
|
||||
dp_size_tl.height,
|
||||
dp_width_left,
|
||||
size.height - dp_size_bl.height,
|
||||
),
|
||||
border.left.style,
|
||||
left_color,
|
||||
BorderSegment::Left,
|
||||
EdgeAaSegmentMask::LEFT | EdgeAaSegmentMask::RIGHT,
|
||||
&mut instances,
|
||||
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + local_size_tl.width,
|
||||
rect.origin.y,
|
||||
rect.origin.x + rect.size.width - local_size_tr.width,
|
||||
rect.origin.y + widths.top,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
dp_size_tl.width,
|
||||
0.0,
|
||||
size.width - dp_size_tr.width,
|
||||
dp_width_top,
|
||||
),
|
||||
border.top.style,
|
||||
top_color,
|
||||
BorderSegment::Top,
|
||||
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::BOTTOM,
|
||||
&mut instances,
|
||||
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + rect.size.width - widths.right,
|
||||
rect.origin.y + local_size_tr.height,
|
||||
rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height - local_size_br.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
size.width - dp_width_right,
|
||||
dp_size_tr.height,
|
||||
size.width,
|
||||
size.height - dp_size_br.height,
|
||||
),
|
||||
border.right.style,
|
||||
right_color,
|
||||
BorderSegment::Right,
|
||||
EdgeAaSegmentMask::RIGHT | EdgeAaSegmentMask::LEFT,
|
||||
&mut instances,
|
||||
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_Y,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + local_size_bl.width,
|
||||
rect.origin.y + rect.size.height - widths.bottom,
|
||||
rect.origin.x + rect.size.width - local_size_br.width,
|
||||
rect.origin.y + rect.size.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
dp_size_bl.width,
|
||||
size.height - dp_width_bottom,
|
||||
size.width - dp_size_br.width,
|
||||
size.height,
|
||||
),
|
||||
border.bottom.style,
|
||||
bottom_color,
|
||||
BorderSegment::Bottom,
|
||||
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::TOP,
|
||||
&mut instances,
|
||||
BrushFlags::SEGMENT_RELATIVE | BrushFlags::SEGMENT_REPEAT_X,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_corner_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.origin.x + local_size_tl.width,
|
||||
rect.origin.y + local_size_tl.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
0.0,
|
||||
0.0,
|
||||
dp_size_tl.width,
|
||||
dp_size_tl.height,
|
||||
),
|
||||
border.left.style,
|
||||
left_color,
|
||||
border.top.style,
|
||||
top_color,
|
||||
DeviceSize::new(dp_width_left, dp_width_top),
|
||||
dp_corner_tl,
|
||||
BorderSegment::TopLeft,
|
||||
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::LEFT,
|
||||
&mut instances,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_corner_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + rect.size.width - local_size_tr.width,
|
||||
rect.origin.y,
|
||||
rect.origin.x + rect.size.width,
|
||||
rect.origin.y + local_size_tr.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
size.width - dp_size_tr.width,
|
||||
0.0,
|
||||
size.width,
|
||||
dp_size_tr.height,
|
||||
),
|
||||
border.top.style,
|
||||
top_color,
|
||||
border.right.style,
|
||||
right_color,
|
||||
DeviceSize::new(dp_width_right, dp_width_top),
|
||||
dp_corner_tr,
|
||||
BorderSegment::TopRight,
|
||||
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::RIGHT,
|
||||
&mut instances,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_corner_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + rect.size.width - local_size_br.width,
|
||||
rect.origin.y + rect.size.height - local_size_br.height,
|
||||
rect.origin.x + rect.size.width,
|
||||
rect.origin.y + rect.size.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
size.width - dp_size_br.width,
|
||||
size.height - dp_size_br.height,
|
||||
size.width,
|
||||
size.height,
|
||||
),
|
||||
border.right.style,
|
||||
right_color,
|
||||
border.bottom.style,
|
||||
bottom_color,
|
||||
DeviceSize::new(dp_width_right, dp_width_bottom),
|
||||
dp_corner_br,
|
||||
BorderSegment::BottomRight,
|
||||
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::RIGHT,
|
||||
&mut instances,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
add_corner_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y + rect.size.height - local_size_bl.height,
|
||||
rect.origin.x + local_size_bl.width,
|
||||
rect.origin.y + rect.size.height,
|
||||
),
|
||||
DeviceRect::from_floats(
|
||||
0.0,
|
||||
size.height - dp_size_bl.height,
|
||||
dp_size_bl.width,
|
||||
size.height,
|
||||
),
|
||||
border.bottom.style,
|
||||
bottom_color,
|
||||
border.left.style,
|
||||
left_color,
|
||||
DeviceSize::new(dp_width_left, dp_width_bottom),
|
||||
dp_corner_bl,
|
||||
BorderSegment::BottomLeft,
|
||||
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::LEFT,
|
||||
&mut instances,
|
||||
&mut segments,
|
||||
);
|
||||
|
||||
BorderRenderTaskInfo {
|
||||
segments,
|
||||
instances,
|
||||
size: size.to_i32(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_brush_segment(
|
||||
image_rect: LayoutRect,
|
||||
task_rect: DeviceRect,
|
||||
brush_flags: BrushFlags,
|
||||
edge_flags: EdgeAaSegmentMask,
|
||||
brush_segments: &mut Vec<BrushSegment>,
|
||||
) {
|
||||
brush_segments.push(
|
||||
BrushSegment::new(
|
||||
image_rect,
|
||||
true,
|
||||
edge_flags,
|
||||
[
|
||||
task_rect.origin.x,
|
||||
task_rect.origin.y,
|
||||
task_rect.origin.x + task_rect.size.width,
|
||||
task_rect.origin.y + task_rect.size.height,
|
||||
],
|
||||
brush_flags,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
fn add_segment(
|
||||
task_rect: DeviceRect,
|
||||
style0: BorderStyle,
|
||||
style1: BorderStyle,
|
||||
color0: ColorF,
|
||||
color1: ColorF,
|
||||
segment: BorderSegment,
|
||||
instances: &mut Vec<BorderInstance>,
|
||||
widths: DeviceSize,
|
||||
radius: DeviceSize,
|
||||
) {
|
||||
let flags = (segment as i32) |
|
||||
((style0 as i32) << 8) |
|
||||
((style1 as i32) << 16);
|
||||
|
||||
let base_instance = BorderInstance {
|
||||
task_origin: DevicePoint::zero(),
|
||||
local_rect: task_rect,
|
||||
flags,
|
||||
color0: color0.premultiplied(),
|
||||
color1: color1.premultiplied(),
|
||||
widths,
|
||||
radius,
|
||||
};
|
||||
|
||||
instances.push(base_instance);
|
||||
}
|
||||
|
||||
fn add_corner_segment(
|
||||
image_rect: LayoutRect,
|
||||
task_rect: DeviceRect,
|
||||
mut style0: BorderStyle,
|
||||
color0: ColorF,
|
||||
mut style1: BorderStyle,
|
||||
color1: ColorF,
|
||||
widths: DeviceSize,
|
||||
radius: DeviceSize,
|
||||
segment: BorderSegment,
|
||||
edge_flags: EdgeAaSegmentMask,
|
||||
instances: &mut Vec<BorderInstance>,
|
||||
brush_segments: &mut Vec<BrushSegment>,
|
||||
) {
|
||||
// TODO(gw): This will need to be a bit more involved when
|
||||
// we support other border types here. For example,
|
||||
// groove / ridge borders will always need to
|
||||
// use two instances.
|
||||
|
||||
if color0.a <= 0.0 && color1.a <= 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if widths.width <= 0.0 && widths.height <= 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let style0_hidden = style0 == BorderStyle::Hidden || style0 == BorderStyle::None;
|
||||
let style1_hidden = style1 == BorderStyle::Hidden || style1 == BorderStyle::None;
|
||||
|
||||
if style0_hidden && style1_hidden {
|
||||
return;
|
||||
}
|
||||
|
||||
if style0_hidden {
|
||||
style0 = style1;
|
||||
}
|
||||
if style1_hidden {
|
||||
style1 = style0;
|
||||
}
|
||||
|
||||
add_segment(
|
||||
task_rect,
|
||||
style0,
|
||||
style1,
|
||||
color0,
|
||||
color1,
|
||||
segment,
|
||||
instances,
|
||||
widths,
|
||||
radius,
|
||||
);
|
||||
|
||||
add_brush_segment(
|
||||
image_rect,
|
||||
task_rect,
|
||||
BrushFlags::SEGMENT_RELATIVE,
|
||||
edge_flags,
|
||||
brush_segments,
|
||||
);
|
||||
}
|
||||
|
||||
fn add_edge_segment(
|
||||
image_rect: LayoutRect,
|
||||
task_rect: DeviceRect,
|
||||
style: BorderStyle,
|
||||
color: ColorF,
|
||||
segment: BorderSegment,
|
||||
edge_flags: EdgeAaSegmentMask,
|
||||
instances: &mut Vec<BorderInstance>,
|
||||
brush_flags: BrushFlags,
|
||||
brush_segments: &mut Vec<BrushSegment>,
|
||||
) {
|
||||
if color.a <= 0.0 {
|
||||
return;
|
||||
}
|
||||
|
||||
if style == BorderStyle::Hidden || style == BorderStyle::None {
|
||||
return;
|
||||
}
|
||||
|
||||
add_segment(
|
||||
task_rect,
|
||||
style,
|
||||
style,
|
||||
color,
|
||||
color,
|
||||
segment,
|
||||
instances,
|
||||
DeviceSize::zero(),
|
||||
DeviceSize::zero(),
|
||||
);
|
||||
|
||||
add_brush_segment(
|
||||
image_rect,
|
||||
task_rect,
|
||||
brush_flags,
|
||||
edge_flags,
|
||||
brush_segments,
|
||||
);
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use internal_types::{FastHashMap, FastHashSet};
|
||||
use picture::PictureCompositeMode;
|
||||
use prim_store::{BrushClipMaskKind, BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient};
|
||||
use prim_store::{CachedGradientIndex, EdgeAaSegmentMask, ImageSource};
|
||||
use prim_store::{BrushSegment, PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
|
||||
use prim_store::{BorderSource, BrushSegment, PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
|
||||
use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitiveCpu};
|
||||
use render_backend::{DocumentView};
|
||||
use resource_cache::{FontInstanceMap, ImageRequest};
|
||||
@ -1636,8 +1636,7 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
}
|
||||
|
||||
let segment = BrushSegment::new(
|
||||
rect.origin,
|
||||
rect.size,
|
||||
rect,
|
||||
true,
|
||||
EdgeAaSegmentMask::empty(),
|
||||
[
|
||||
@ -1741,13 +1740,15 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
|
||||
let prim = PrimitiveContainer::Brush(match border.source {
|
||||
NinePatchBorderSource::Image(image_key) => {
|
||||
let source = BorderSource::Image(ImageRequest {
|
||||
key: image_key,
|
||||
rendering: ImageRendering::Auto,
|
||||
tile: None,
|
||||
});
|
||||
|
||||
BrushPrimitive::new(
|
||||
BrushKind::Border {
|
||||
request: ImageRequest {
|
||||
key: image_key,
|
||||
rendering: ImageRendering::Auto,
|
||||
tile: None,
|
||||
},
|
||||
source
|
||||
},
|
||||
Some(descriptor),
|
||||
)
|
||||
@ -1966,20 +1967,18 @@ impl<'a> DisplayListFlattener<'a> {
|
||||
*text_color,
|
||||
font_instance.bg_color,
|
||||
render_mode,
|
||||
font_instance.subpx_dir,
|
||||
flags,
|
||||
font_instance.platform_options,
|
||||
font_instance.variations.clone(),
|
||||
);
|
||||
TextRunPrimitiveCpu {
|
||||
font: prim_font,
|
||||
TextRunPrimitiveCpu::new(
|
||||
prim_font,
|
||||
run_offset,
|
||||
glyph_range,
|
||||
glyph_gpu_blocks: Vec::new(),
|
||||
glyph_keys: Vec::new(),
|
||||
offset: run_offset,
|
||||
shadow: false,
|
||||
Vec::new(),
|
||||
false,
|
||||
glyph_raster_space,
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
self.add_primitive(
|
||||
|
@ -4,8 +4,7 @@
|
||||
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use api::DeviceIntPoint;
|
||||
use api::GlyphKey;
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat};
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey};
|
||||
use internal_types::FastHashMap;
|
||||
use render_task::RenderTaskCache;
|
||||
#[cfg(feature = "pathfinder")]
|
||||
|
@ -2,11 +2,13 @@
|
||||
* 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 api::{ColorF, ColorU};
|
||||
use api::{ColorF, ColorU, DevicePoint};
|
||||
use api::{FontInstanceFlags, FontInstancePlatformOptions};
|
||||
use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
|
||||
use api::{GlyphDimensions, GlyphKey, LayoutToWorldTransform, SubpixelDirection};
|
||||
use api::{GlyphIndex, GlyphDimensions};
|
||||
use api::{LayoutPoint, LayoutToWorldTransform, WorldPoint};
|
||||
use app_units::Au;
|
||||
use euclid::approxeq::ApproxEq;
|
||||
use internal_types::ResourceCacheError;
|
||||
use platform::font::FontContext;
|
||||
use rayon::ThreadPool;
|
||||
@ -127,7 +129,27 @@ impl FontTransform {
|
||||
}
|
||||
|
||||
pub fn flip_y(&self) -> Self {
|
||||
FontTransform::new(self.scale_x, -self.skew_y, self.skew_y, -self.scale_y)
|
||||
FontTransform::new(self.scale_x, -self.skew_x, self.skew_y, -self.scale_y)
|
||||
}
|
||||
|
||||
pub fn transform(&self, point: &LayoutPoint) -> WorldPoint {
|
||||
WorldPoint::new(
|
||||
self.scale_x * point.x + self.skew_x * point.y,
|
||||
self.skew_y * point.x + self.scale_y * point.y,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_subpx_dir(&self) -> SubpixelDirection {
|
||||
if self.skew_y.approx_eq(&0.0) {
|
||||
// The X axis is not projected onto the Y axis
|
||||
SubpixelDirection::Horizontal
|
||||
} else if self.scale_x.approx_eq(&0.0) {
|
||||
// The X axis has been swapped with the Y axis
|
||||
SubpixelDirection::Vertical
|
||||
} else {
|
||||
// Use subpixel precision on all axes
|
||||
SubpixelDirection::Mixed
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,7 +173,6 @@ pub struct FontInstance {
|
||||
pub color: ColorU,
|
||||
pub bg_color: ColorU,
|
||||
pub render_mode: FontRenderMode,
|
||||
pub subpx_dir: SubpixelDirection,
|
||||
pub flags: FontInstanceFlags,
|
||||
pub platform_options: Option<FontInstancePlatformOptions>,
|
||||
pub variations: Vec<FontVariation>,
|
||||
@ -165,7 +186,6 @@ impl FontInstance {
|
||||
color: ColorF,
|
||||
bg_color: ColorU,
|
||||
render_mode: FontRenderMode,
|
||||
subpx_dir: SubpixelDirection,
|
||||
flags: FontInstanceFlags,
|
||||
platform_options: Option<FontInstancePlatformOptions>,
|
||||
variations: Vec<FontVariation>,
|
||||
@ -180,7 +200,6 @@ impl FontInstance {
|
||||
color: color.into(),
|
||||
bg_color,
|
||||
render_mode,
|
||||
subpx_dir,
|
||||
flags,
|
||||
platform_options,
|
||||
variations,
|
||||
@ -196,12 +215,38 @@ impl FontInstance {
|
||||
if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel }
|
||||
}
|
||||
|
||||
pub fn disable_subpixel_aa(&mut self) {
|
||||
self.render_mode = self.render_mode.limit_by(FontRenderMode::Alpha);
|
||||
}
|
||||
|
||||
pub fn disable_subpixel_position(&mut self) {
|
||||
self.flags.remove(FontInstanceFlags::SUBPIXEL_POSITION);
|
||||
}
|
||||
|
||||
pub fn use_subpixel_position(&self) -> bool {
|
||||
self.flags.contains(FontInstanceFlags::SUBPIXEL_POSITION) &&
|
||||
self.render_mode != FontRenderMode::Mono
|
||||
}
|
||||
|
||||
pub fn get_subpx_dir(&self) -> SubpixelDirection {
|
||||
if self.use_subpixel_position() {
|
||||
let mut subpx_dir = self.transform.get_subpx_dir();
|
||||
if self.flags.contains(FontInstanceFlags::TRANSPOSE) {
|
||||
subpx_dir = subpx_dir.swap_xy();
|
||||
}
|
||||
subpx_dir
|
||||
} else {
|
||||
SubpixelDirection::None
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_subpx_offset(&self, glyph: &GlyphKey) -> (f64, f64) {
|
||||
match self.subpx_dir {
|
||||
SubpixelDirection::None => (0.0, 0.0),
|
||||
SubpixelDirection::Horizontal => (glyph.subpixel_offset.into(), 0.0),
|
||||
SubpixelDirection::Vertical => (0.0, glyph.subpixel_offset.into()),
|
||||
if self.use_subpixel_position() {
|
||||
let (dx, dy) = glyph.subpixel_offset;
|
||||
(dx.into(), dy.into())
|
||||
} else {
|
||||
(0.0, 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,6 +272,111 @@ impl FontInstance {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
|
||||
pub enum SubpixelDirection {
|
||||
None = 0,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
Mixed,
|
||||
}
|
||||
|
||||
impl SubpixelDirection {
|
||||
// Limit the subpixel direction to what is supported by the glyph format.
|
||||
pub fn limit_by(self, glyph_format: GlyphFormat) -> Self {
|
||||
match glyph_format {
|
||||
GlyphFormat::Bitmap |
|
||||
GlyphFormat::ColorBitmap => SubpixelDirection::None,
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap_xy(self) -> Self {
|
||||
match self {
|
||||
SubpixelDirection::None | SubpixelDirection::Mixed => self,
|
||||
SubpixelDirection::Horizontal => SubpixelDirection::Vertical,
|
||||
SubpixelDirection::Vertical => SubpixelDirection::Horizontal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub enum SubpixelOffset {
|
||||
Zero = 0,
|
||||
Quarter = 1,
|
||||
Half = 2,
|
||||
ThreeQuarters = 3,
|
||||
}
|
||||
|
||||
impl SubpixelOffset {
|
||||
// Skia quantizes subpixel offsets into 1/4 increments.
|
||||
// Given the absolute position, return the quantized increment
|
||||
fn quantize(pos: f32) -> Self {
|
||||
// Following the conventions of Gecko and Skia, we want
|
||||
// to quantize the subpixel position, such that abs(pos) gives:
|
||||
// [0.0, 0.125) -> Zero
|
||||
// [0.125, 0.375) -> Quarter
|
||||
// [0.375, 0.625) -> Half
|
||||
// [0.625, 0.875) -> ThreeQuarters,
|
||||
// [0.875, 1.0) -> Zero
|
||||
// The unit tests below check for this.
|
||||
let apos = ((pos - pos.floor()) * 8.0) as i32;
|
||||
|
||||
match apos {
|
||||
0 | 7 => SubpixelOffset::Zero,
|
||||
1...2 => SubpixelOffset::Quarter,
|
||||
3...4 => SubpixelOffset::Half,
|
||||
5...6 => SubpixelOffset::ThreeQuarters,
|
||||
_ => unreachable!("bug: unexpected quantized result"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<f64> for SubpixelOffset {
|
||||
fn into(self) -> f64 {
|
||||
match self {
|
||||
SubpixelOffset::Zero => 0.0,
|
||||
SubpixelOffset::Quarter => 0.25,
|
||||
SubpixelOffset::Half => 0.5,
|
||||
SubpixelOffset::ThreeQuarters => 0.75,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct GlyphKey {
|
||||
pub index: u32,
|
||||
pub subpixel_offset: (SubpixelOffset, SubpixelOffset),
|
||||
}
|
||||
|
||||
impl GlyphKey {
|
||||
pub fn new(
|
||||
index: u32,
|
||||
point: DevicePoint,
|
||||
subpx_dir: SubpixelDirection,
|
||||
) -> GlyphKey {
|
||||
let (dx, dy) = match subpx_dir {
|
||||
SubpixelDirection::None => (0.0, 0.0),
|
||||
SubpixelDirection::Horizontal => (point.x, 0.0),
|
||||
SubpixelDirection::Vertical => (0.0, point.y),
|
||||
SubpixelDirection::Mixed => (point.x, point.y),
|
||||
};
|
||||
|
||||
GlyphKey {
|
||||
index,
|
||||
subpixel_offset: (
|
||||
SubpixelOffset::quantize(dx),
|
||||
SubpixelOffset::quantize(dy),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
@ -395,11 +545,17 @@ impl GlyphRasterizer {
|
||||
pub fn get_glyph_dimensions(
|
||||
&mut self,
|
||||
font: &FontInstance,
|
||||
glyph_key: &GlyphKey,
|
||||
glyph_index: GlyphIndex,
|
||||
) -> Option<GlyphDimensions> {
|
||||
let glyph_key = GlyphKey::new(
|
||||
glyph_index,
|
||||
DevicePoint::zero(),
|
||||
SubpixelDirection::None,
|
||||
);
|
||||
|
||||
self.font_contexts
|
||||
.lock_shared_context()
|
||||
.get_glyph_dimensions(font, glyph_key)
|
||||
.get_glyph_dimensions(font, &glyph_key)
|
||||
}
|
||||
|
||||
pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option<u32> {
|
||||
@ -454,23 +610,6 @@ impl AddFont for FontContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq, Debug, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct GlyphRequest {
|
||||
pub key: GlyphKey,
|
||||
pub font: FontInstance,
|
||||
}
|
||||
|
||||
impl GlyphRequest {
|
||||
pub fn new(font: &FontInstance, key: &GlyphKey) -> Self {
|
||||
GlyphRequest {
|
||||
key: key.clone(),
|
||||
font: font.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(in glyph_rasterizer) struct GlyphRasterJob {
|
||||
key: GlyphKey,
|
||||
@ -511,13 +650,13 @@ mod test_glyph_rasterizer {
|
||||
use api::DeviceIntSize;
|
||||
use render_task::{RenderTaskCache, RenderTaskTree};
|
||||
use profiler::TextureCacheProfileCounters;
|
||||
use api::{FontKey, FontTemplate, FontRenderMode, GlyphKey,
|
||||
IdNamespace, LayoutPoint, ColorF, ColorU, SubpixelDirection};
|
||||
use api::{FontKey, FontTemplate, FontRenderMode,
|
||||
IdNamespace, ColorF, ColorU, DevicePoint};
|
||||
use render_backend::FrameId;
|
||||
use app_units::Au;
|
||||
use thread_profiler::register_thread_with_profiler;
|
||||
use std::sync::Arc;
|
||||
use glyph_rasterizer::{GlyphRasterizer, FontInstance};
|
||||
use glyph_rasterizer::{FontInstance, GlyphKey, GlyphRasterizer};
|
||||
|
||||
let worker = ThreadPoolBuilder::new()
|
||||
.thread_name(|idx|{ format!("WRWorker#{}", idx) })
|
||||
@ -550,19 +689,18 @@ mod test_glyph_rasterizer {
|
||||
ColorF::new(0.0, 0.0, 0.0, 1.0),
|
||||
ColorU::new(0, 0, 0, 0),
|
||||
FontRenderMode::Subpixel,
|
||||
SubpixelDirection::Horizontal,
|
||||
Default::default(),
|
||||
None,
|
||||
Vec::new(),
|
||||
);
|
||||
let subpx_dir = font.get_subpx_dir();
|
||||
|
||||
let mut glyph_keys = Vec::with_capacity(200);
|
||||
for i in 0 .. 200 {
|
||||
glyph_keys.push(GlyphKey::new(
|
||||
i,
|
||||
LayoutPoint::zero(),
|
||||
font.render_mode,
|
||||
font.subpx_dir,
|
||||
DevicePoint::zero(),
|
||||
subpx_dir,
|
||||
));
|
||||
}
|
||||
|
||||
@ -590,4 +728,48 @@ mod test_glyph_rasterizer {
|
||||
&mut TextureCacheProfileCounters::new(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subpx_quantize() {
|
||||
use glyph_rasterizer::SubpixelOffset;
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.0), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(-0.0), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.1), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.01), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.05), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.12), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.124), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.125), SubpixelOffset::Quarter);
|
||||
assert_eq!(SubpixelOffset::quantize(0.2), SubpixelOffset::Quarter);
|
||||
assert_eq!(SubpixelOffset::quantize(0.25), SubpixelOffset::Quarter);
|
||||
assert_eq!(SubpixelOffset::quantize(0.33), SubpixelOffset::Quarter);
|
||||
assert_eq!(SubpixelOffset::quantize(0.374), SubpixelOffset::Quarter);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.375), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(0.4), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(0.5), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(0.58), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(0.624), SubpixelOffset::Half);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.625), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(SubpixelOffset::quantize(0.67), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(SubpixelOffset::quantize(0.7), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(SubpixelOffset::quantize(0.78), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(SubpixelOffset::quantize(0.874), SubpixelOffset::ThreeQuarters);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(0.875), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.89), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.91), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.967), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(0.999), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(SubpixelOffset::quantize(-1.0), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(1.0), SubpixelOffset::Zero);
|
||||
assert_eq!(SubpixelOffset::quantize(1.5), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(-1.625), SubpixelOffset::Half);
|
||||
assert_eq!(SubpixelOffset::quantize(-4.33), SubpixelOffset::ThreeQuarters);
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,15 @@
|
||||
//! Module only available when pathfinder is deactivated when webrender is
|
||||
//! compiled regularly (i.e. any configuration without feature = "pathfinder")
|
||||
|
||||
use api::{GlyphKey, ImageData, ImageDescriptor, ImageFormat};
|
||||
use api::{ImageData, ImageDescriptor, ImageFormat};
|
||||
use device::TextureFilter;
|
||||
use euclid::size2;
|
||||
use gpu_types::UvRectKind;
|
||||
use rayon::prelude::*;
|
||||
use std::sync::{Arc, MutexGuard};
|
||||
use platform::font::FontContext;
|
||||
use glyph_rasterizer::{FontInstance, FontContexts, GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs, GlyphRasterResult};
|
||||
use glyph_rasterizer::{FontInstance, FontContexts, GlyphKey};
|
||||
use glyph_rasterizer::{GlyphRasterizer, GlyphRasterJob, GlyphRasterJobs, GlyphRasterResult};
|
||||
use glyph_cache::{GlyphCache, CachedGlyphInfo, GlyphCacheEntry};
|
||||
use texture_cache::{TextureCache, TextureCacheHandle};
|
||||
use gpu_cache::GpuCache;
|
||||
@ -202,4 +203,4 @@ impl GlyphRasterizer {
|
||||
// we can schedule removing the fonts if needed.
|
||||
self.remove_dead_fonts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
//! Module only available when pathfinder is activated
|
||||
|
||||
use api::{DeviceIntPoint, DeviceIntSize, DevicePixel, FontRenderMode, FontKey, FontTemplate, GlyphKey, NativeFontHandle};
|
||||
use api::{DeviceIntPoint, DeviceIntSize, DevicePixel, FontRenderMode, FontKey, FontTemplate, NativeFontHandle};
|
||||
use euclid::{TypedPoint2D, TypedSize2D, TypedVector2D};
|
||||
use pathfinder_font_renderer;
|
||||
use pathfinder_partitioner::mesh::Mesh as PathfinderMesh;
|
||||
@ -20,7 +20,7 @@ use internal_types::ResourceCacheError;
|
||||
use glyph_cache::{GlyphCache, GlyphCacheEntry, CachedGlyphInfo};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::f32;
|
||||
use glyph_rasterizer::{FontInstance, GlyphRasterizer, GlyphFormat, FontContexts};
|
||||
use glyph_rasterizer::{FontInstance, GlyphRasterizer, GlyphFormat, GlyphKey, FontContexts};
|
||||
use texture_cache::TextureCache;
|
||||
use gpu_cache::GpuCache;
|
||||
use profiler::TextureCacheProfileCounters;
|
||||
@ -190,8 +190,9 @@ impl GlyphRasterizer {
|
||||
size: font.size,
|
||||
};
|
||||
|
||||
// TODO: pathfinder will need to support 2D subpixel offset
|
||||
let pathfinder_subpixel_offset =
|
||||
pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset as u8);
|
||||
pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
|
||||
let pathfinder_glyph_key =
|
||||
pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
|
||||
pathfinder_subpixel_offset);
|
||||
@ -272,9 +273,10 @@ fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
|
||||
size: font.size,
|
||||
};
|
||||
|
||||
// TODO: pathfinder will need to support 2D subpixel offset
|
||||
let pathfinder_subpixel_offset =
|
||||
pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset as u8);
|
||||
let glyph_subpixel_offset: f64 = glyph_key.subpixel_offset.into();
|
||||
pathfinder_font_renderer::SubpixelOffset(glyph_key.subpixel_offset.0 as u8);
|
||||
let glyph_subpixel_offset: f64 = glyph_key.subpixel_offset.0.into();
|
||||
let pathfinder_glyph_key = pathfinder_font_renderer::GlyphKey::new(glyph_key.index,
|
||||
pathfinder_subpixel_offset);
|
||||
|
||||
@ -311,4 +313,4 @@ fn request_render_task_from_pathfinder(glyph_key: &GlyphKey,
|
||||
Ok(root_task_id)
|
||||
}
|
||||
|
||||
pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
|
||||
pub struct NativeFontHandleWrapper<'a>(pub &'a NativeFontHandle);
|
||||
|
@ -2,7 +2,8 @@
|
||||
* 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 api::{DevicePoint, LayoutToWorldTransform, WorldToLayoutTransform};
|
||||
use api::{DevicePoint, DeviceSize, DeviceRect, LayoutToWorldTransform};
|
||||
use api::{PremultipliedColorF, WorldToLayoutTransform};
|
||||
use gpu_cache::{GpuCacheAddress, GpuDataRequest};
|
||||
use prim_store::{VECS_PER_SEGMENT, EdgeAaSegmentMask};
|
||||
use render_task::RenderTaskAddress;
|
||||
@ -79,6 +80,35 @@ pub struct BlurInstance {
|
||||
pub blur_direction: BlurDirection,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub enum BorderSegment {
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomRight,
|
||||
BottomLeft,
|
||||
Left,
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderInstance {
|
||||
pub task_origin: DevicePoint,
|
||||
pub local_rect: DeviceRect,
|
||||
pub color0: PremultipliedColorF,
|
||||
pub color1: PremultipliedColorF,
|
||||
pub flags: i32,
|
||||
pub widths: DeviceSize,
|
||||
pub radius: DeviceSize,
|
||||
}
|
||||
|
||||
/// A clipping primitive drawn into the clipping mask.
|
||||
/// Could be an image or a rectangle, which defines the
|
||||
/// way `address` is treated.
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
use api::{ColorU, FontKey, FontRenderMode, GlyphDimensions};
|
||||
use api::{FontInstanceFlags, FontVariation, NativeFontHandle};
|
||||
use api::{GlyphKey, SubpixelDirection};
|
||||
use app_units::Au;
|
||||
use core_foundation::array::{CFArray, CFArrayRef};
|
||||
use core_foundation::base::TCFType;
|
||||
@ -27,7 +26,7 @@ use core_text;
|
||||
use core_text::font::{CTFont, CTFontRef};
|
||||
use core_text::font_descriptor::{kCTFontDefaultOrientation, kCTFontColorGlyphsTrait};
|
||||
use gamma_lut::{ColorLut, GammaLut};
|
||||
use glyph_rasterizer::{FontInstance, FontTransform};
|
||||
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use glyph_rasterizer::NativeFontHandleWrapper;
|
||||
#[cfg(not(feature = "pathfinder"))]
|
||||
@ -463,7 +462,7 @@ impl FontContext {
|
||||
// In mono mode the color of the font is irrelevant.
|
||||
font.color = ColorU::new(255, 255, 255, 255);
|
||||
// Subpixel positioning is disabled in mono mode.
|
||||
font.subpx_dir = SubpixelDirection::None;
|
||||
font.disable_subpixel_position();
|
||||
}
|
||||
FontRenderMode::Alpha => {
|
||||
font.color = if font.flags.contains(FontInstanceFlags::FONT_SMOOTHING) {
|
||||
|
@ -2,9 +2,9 @@
|
||||
* 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 api::{ColorU, GlyphDimensions, GlyphKey, FontKey, FontRenderMode};
|
||||
use api::{ColorU, GlyphDimensions, FontKey, FontRenderMode};
|
||||
use api::{FontInstancePlatformOptions, FontLCDFilter, FontHinting};
|
||||
use api::{FontInstanceFlags, NativeFontHandle, SubpixelDirection};
|
||||
use api::{FontInstanceFlags, NativeFontHandle};
|
||||
use freetype::freetype::{FT_BBox, FT_Outline_Translate, FT_Pixel_Mode, FT_Render_Mode};
|
||||
use freetype::freetype::{FT_Done_Face, FT_Error, FT_Get_Char_Index, FT_Int32};
|
||||
use freetype::freetype::{FT_Done_FreeType, FT_Library_SetLcdFilter, FT_Pos};
|
||||
@ -18,7 +18,7 @@ use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHIN
|
||||
use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT};
|
||||
use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES};
|
||||
use freetype::succeeded;
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterResult, RasterizedGlyph};
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey, GlyphRasterResult, RasterizedGlyph};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use glyph_rasterizer::NativeFontHandleWrapper;
|
||||
use internal_types::{FastHashMap, ResourceCacheError};
|
||||
@ -253,9 +253,10 @@ impl FontContext {
|
||||
(FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
|
||||
(FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
|
||||
(FontHinting::LCD, FontRenderMode::Subpixel) => {
|
||||
load_flags = match font.subpx_dir {
|
||||
SubpixelDirection::Vertical => FT_LOAD_TARGET_LCD_V,
|
||||
_ => FT_LOAD_TARGET_LCD,
|
||||
load_flags = if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
|
||||
FT_LOAD_TARGET_LCD_V
|
||||
} else {
|
||||
FT_LOAD_TARGET_LCD
|
||||
};
|
||||
if font.flags.contains(FontInstanceFlags::FORCE_AUTOHINT) {
|
||||
load_flags |= FT_LOAD_FORCE_AUTOHINT;
|
||||
@ -375,31 +376,29 @@ impl FontContext {
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the subpixel offset to floats.
|
||||
let (dx, dy) = font.get_subpx_offset(glyph);
|
||||
|
||||
// Apply extra pixel of padding for subpixel AA, due to the filter.
|
||||
let padding = match font.render_mode {
|
||||
FontRenderMode::Subpixel => (self.lcd_extra_pixels * 64) as FT_Pos,
|
||||
FontRenderMode::Alpha |
|
||||
FontRenderMode::Mono => 0 as FT_Pos,
|
||||
};
|
||||
if font.render_mode == FontRenderMode::Subpixel {
|
||||
let padding = (self.lcd_extra_pixels * 64) as FT_Pos;
|
||||
if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
|
||||
cbox.yMin -= padding;
|
||||
cbox.yMax += padding;
|
||||
} else {
|
||||
cbox.xMin -= padding;
|
||||
cbox.xMax += padding;
|
||||
}
|
||||
}
|
||||
|
||||
// Offset the bounding box by subpixel positioning.
|
||||
// Convert to 26.6 fixed point format for FT.
|
||||
match font.subpx_dir {
|
||||
SubpixelDirection::None => {}
|
||||
SubpixelDirection::Horizontal => {
|
||||
let dx = (dx * 64.0 + 0.5) as FT_Long;
|
||||
cbox.xMin += dx - padding;
|
||||
cbox.xMax += dx + padding;
|
||||
}
|
||||
SubpixelDirection::Vertical => {
|
||||
let dy = (dy * 64.0 + 0.5) as FT_Long;
|
||||
cbox.yMin += dy - padding;
|
||||
cbox.yMax += dy + padding;
|
||||
}
|
||||
}
|
||||
let (dx, dy) = font.get_subpx_offset(glyph);
|
||||
let (dx, dy) = (
|
||||
(dx * 64.0 + 0.5) as FT_Pos,
|
||||
-(dy * 64.0 + 0.5) as FT_Pos,
|
||||
);
|
||||
cbox.xMin += dx;
|
||||
cbox.xMax += dx;
|
||||
cbox.yMin += dy;
|
||||
cbox.yMax += dy;
|
||||
|
||||
// Outset the box to device pixel boundaries
|
||||
cbox.xMin &= !63;
|
||||
@ -522,7 +521,7 @@ impl FontContext {
|
||||
// In mono mode the color of the font is irrelevant.
|
||||
font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF);
|
||||
// Subpixel positioning is disabled in mono mode.
|
||||
font.subpx_dir = SubpixelDirection::None;
|
||||
font.disable_subpixel_position();
|
||||
}
|
||||
FontRenderMode::Alpha | FontRenderMode::Subpixel => {
|
||||
// We don't do any preblending with FreeType currently, so the color is not used.
|
||||
@ -539,8 +538,10 @@ impl FontContext {
|
||||
) -> bool {
|
||||
// Get the subpixel offsets in FT 26.6 format.
|
||||
let (dx, dy) = font.get_subpx_offset(key);
|
||||
let dx = (dx * 64.0 + 0.5) as FT_Long;
|
||||
let dy = (dy * 64.0 + 0.5) as FT_Long;
|
||||
let (dx, dy) = (
|
||||
(dx * 64.0 + 0.5) as FT_Pos,
|
||||
-(dy * 64.0 + 0.5) as FT_Pos,
|
||||
);
|
||||
|
||||
// Move the outline curves to be at the origin, taking
|
||||
// into account the subpixel positioning.
|
||||
@ -565,11 +566,14 @@ impl FontContext {
|
||||
};
|
||||
unsafe { FT_Library_SetLcdFilter(self.lib, filter) };
|
||||
}
|
||||
let render_mode = match (font.render_mode, font.subpx_dir) {
|
||||
(FontRenderMode::Mono, _) => FT_Render_Mode::FT_RENDER_MODE_MONO,
|
||||
(FontRenderMode::Alpha, _) => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
|
||||
(FontRenderMode::Subpixel, SubpixelDirection::Vertical) => FT_Render_Mode::FT_RENDER_MODE_LCD_V,
|
||||
(FontRenderMode::Subpixel, _) => FT_Render_Mode::FT_RENDER_MODE_LCD,
|
||||
let render_mode = match font.render_mode {
|
||||
FontRenderMode::Mono => FT_Render_Mode::FT_RENDER_MODE_MONO,
|
||||
FontRenderMode::Alpha => FT_Render_Mode::FT_RENDER_MODE_NORMAL,
|
||||
FontRenderMode::Subpixel => if font.flags.contains(FontInstanceFlags::LCD_VERTICAL) {
|
||||
FT_Render_Mode::FT_RENDER_MODE_LCD_V
|
||||
} else {
|
||||
FT_Render_Mode::FT_RENDER_MODE_LCD
|
||||
},
|
||||
};
|
||||
let result = unsafe { FT_Render_Glyph(slot, render_mode) };
|
||||
if !succeeded(result) {
|
||||
|
@ -3,10 +3,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{FontInstanceFlags, FontKey, FontRenderMode};
|
||||
use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection};
|
||||
use api::{ColorU, GlyphDimensions};
|
||||
use dwrote;
|
||||
use gamma_lut::ColorLut;
|
||||
use glyph_rasterizer::{FontInstance, FontTransform};
|
||||
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey};
|
||||
use internal_types::{FastHashMap, ResourceCacheError};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::sync::Arc;
|
||||
@ -372,7 +372,7 @@ impl FontContext {
|
||||
// In mono mode the color of the font is irrelevant.
|
||||
font.color = ColorU::new(255, 255, 255, 255);
|
||||
// Subpixel positioning is disabled in mono mode.
|
||||
font.subpx_dir = SubpixelDirection::None;
|
||||
font.disable_subpixel_position();
|
||||
}
|
||||
FontRenderMode::Alpha => {
|
||||
font.color = font.color.luminance_color().quantize();
|
||||
@ -469,4 +469,4 @@ impl<'a> From<NativeFontHandleWrapper<'a>> for PathfinderComPtr<IDWriteFontFace>
|
||||
let face = font.create_font_face();
|
||||
unsafe { PathfinderComPtr::new(face.as_ptr()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,13 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion};
|
||||
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode};
|
||||
use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset};
|
||||
use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode};
|
||||
use api::{FilterOp, GlyphInstance, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset};
|
||||
use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D};
|
||||
use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat, DeviceIntSideOffsets};
|
||||
use border::{BorderCornerInstance, BorderEdgeKind};
|
||||
use api::{BorderWidths, LayoutToWorldScale, NormalBorder};
|
||||
use app_units::Au;
|
||||
use border::{BorderCacheKey, BorderCornerInstance, BorderRenderTaskInfo, BorderEdgeKind};
|
||||
use box_shadow::BLUR_SAMPLE_SCALE;
|
||||
use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId};
|
||||
use clip_scroll_node::ClipScrollNode;
|
||||
@ -15,7 +17,7 @@ use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSo
|
||||
use clip::{ClipSourcesHandle, ClipWorkItem};
|
||||
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
|
||||
use frame_builder::PrimitiveRunContext;
|
||||
use glyph_rasterizer::{FontInstance, FontTransform};
|
||||
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey};
|
||||
use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest,
|
||||
ToGpuBlocks};
|
||||
use gpu_types::{BrushFlags, ClipChainRectIndex};
|
||||
@ -255,6 +257,18 @@ pub struct VisibleGradientTile {
|
||||
pub handle: GpuCacheHandle,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BorderSource {
|
||||
Image(ImageRequest),
|
||||
Border {
|
||||
handle: Option<RenderTaskCacheEntryHandle>,
|
||||
cache_key: BorderCacheKey,
|
||||
task_info: Option<BorderRenderTaskInfo>,
|
||||
border: NormalBorder,
|
||||
widths: BorderWidths,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BrushKind {
|
||||
Solid {
|
||||
@ -307,7 +321,7 @@ pub enum BrushKind {
|
||||
visible_tiles: Vec<VisibleGradientTile>,
|
||||
},
|
||||
Border {
|
||||
request: ImageRequest,
|
||||
source: BorderSource,
|
||||
},
|
||||
}
|
||||
|
||||
@ -353,7 +367,7 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum BrushSegmentTaskId {
|
||||
RenderTaskId(RenderTaskId),
|
||||
Opaque,
|
||||
@ -369,7 +383,7 @@ impl BrushSegmentTaskId {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BrushSegment {
|
||||
pub local_rect: LayoutRect,
|
||||
pub clip_task_id: BrushSegmentTaskId,
|
||||
@ -381,15 +395,14 @@ pub struct BrushSegment {
|
||||
|
||||
impl BrushSegment {
|
||||
pub fn new(
|
||||
origin: LayoutPoint,
|
||||
size: LayoutSize,
|
||||
rect: LayoutRect,
|
||||
may_need_clip_mask: bool,
|
||||
edge_flags: EdgeAaSegmentMask,
|
||||
extra_data: [f32; 4],
|
||||
brush_flags: BrushFlags,
|
||||
) -> BrushSegment {
|
||||
BrushSegment {
|
||||
local_rect: LayoutRect::new(origin, size),
|
||||
local_rect: rect,
|
||||
clip_task_id: BrushSegmentTaskId::Opaque,
|
||||
may_need_clip_mask,
|
||||
edge_flags,
|
||||
@ -761,11 +774,32 @@ pub struct TextRunPrimitiveCpu {
|
||||
pub glyph_range: ItemRange<GlyphInstance>,
|
||||
pub glyph_keys: Vec<GlyphKey>,
|
||||
pub glyph_gpu_blocks: Vec<GpuBlockData>,
|
||||
pub glyph_transform: (DevicePixelScale, FontTransform),
|
||||
pub shadow: bool,
|
||||
pub glyph_raster_space: GlyphRasterSpace,
|
||||
}
|
||||
|
||||
impl TextRunPrimitiveCpu {
|
||||
pub fn new(
|
||||
font: FontInstance,
|
||||
offset: LayoutVector2D,
|
||||
glyph_range: ItemRange<GlyphInstance>,
|
||||
glyph_keys: Vec<GlyphKey>,
|
||||
shadow: bool,
|
||||
glyph_raster_space: GlyphRasterSpace,
|
||||
) -> Self {
|
||||
TextRunPrimitiveCpu {
|
||||
font,
|
||||
offset,
|
||||
glyph_range,
|
||||
glyph_keys,
|
||||
glyph_gpu_blocks: Vec::new(),
|
||||
glyph_transform: (DevicePixelScale::new(1.0), FontTransform::identity()),
|
||||
shadow,
|
||||
glyph_raster_space,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_font(
|
||||
&self,
|
||||
device_pixel_scale: DevicePixelScale,
|
||||
@ -777,7 +811,8 @@ impl TextRunPrimitiveCpu {
|
||||
if transform.has_perspective_component() ||
|
||||
!transform.has_2d_inverse() ||
|
||||
self.glyph_raster_space != GlyphRasterSpace::Screen {
|
||||
font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha);
|
||||
font.disable_subpixel_aa();
|
||||
font.disable_subpixel_position();
|
||||
} else {
|
||||
font.transform = FontTransform::from(&transform).quantize();
|
||||
}
|
||||
@ -794,7 +829,7 @@ impl TextRunPrimitiveCpu {
|
||||
frame_building_state: &mut FrameBuildingState,
|
||||
) {
|
||||
if !allow_subpixel_aa && self.font.bg_color.a == 0 {
|
||||
self.font.render_mode = self.font.render_mode.limit_by(FontRenderMode::Alpha);
|
||||
self.font.disable_subpixel_aa();
|
||||
}
|
||||
|
||||
let font = self.get_font(device_pixel_scale, transform);
|
||||
@ -803,8 +838,8 @@ impl TextRunPrimitiveCpu {
|
||||
// TODO(gw): In the future, remove `glyph_instances`
|
||||
// completely, and just reference the glyphs
|
||||
// directly from the display list.
|
||||
if self.glyph_keys.is_empty() {
|
||||
let subpx_dir = font.subpx_dir.limit_by(font.render_mode);
|
||||
if self.glyph_keys.is_empty() || self.glyph_transform != (device_pixel_scale, font.transform) {
|
||||
let subpx_dir = font.get_subpx_dir();
|
||||
let src_glyphs = display_list.get(self.glyph_range);
|
||||
|
||||
// TODO(gw): If we support chunks() on AuxIter
|
||||
@ -812,7 +847,10 @@ impl TextRunPrimitiveCpu {
|
||||
// be much simpler...
|
||||
let mut gpu_block = [0.0; 4];
|
||||
for (i, src) in src_glyphs.enumerate() {
|
||||
let key = GlyphKey::new(src.index, src.point, font.render_mode, subpx_dir);
|
||||
let layout_offset = src.point + self.offset;
|
||||
let world_offset = font.transform.transform(&layout_offset);
|
||||
let device_offset = device_pixel_scale.transform_point(&world_offset);
|
||||
let key = GlyphKey::new(src.index, device_offset, subpx_dir);
|
||||
self.glyph_keys.push(key);
|
||||
|
||||
// Two glyphs are packed per GPU block.
|
||||
@ -832,6 +870,8 @@ impl TextRunPrimitiveCpu {
|
||||
if (self.glyph_keys.len() & 1) != 0 {
|
||||
self.glyph_gpu_blocks.push(gpu_block.into());
|
||||
}
|
||||
|
||||
self.glyph_transform = (device_pixel_scale, font.transform);
|
||||
}
|
||||
|
||||
frame_building_state.resource_cache
|
||||
@ -1090,25 +1130,22 @@ impl PrimitiveContainer {
|
||||
pub fn create_shadow(&self, shadow: &Shadow) -> PrimitiveContainer {
|
||||
match *self {
|
||||
PrimitiveContainer::TextRun(ref info) => {
|
||||
let mut render_mode = info.font.render_mode;
|
||||
|
||||
let mut font = FontInstance {
|
||||
color: shadow.color.into(),
|
||||
..info.font.clone()
|
||||
};
|
||||
if shadow.blur_radius > 0.0 {
|
||||
render_mode = render_mode.limit_by(FontRenderMode::Alpha);
|
||||
font.disable_subpixel_aa();
|
||||
}
|
||||
|
||||
PrimitiveContainer::TextRun(TextRunPrimitiveCpu {
|
||||
font: FontInstance {
|
||||
color: shadow.color.into(),
|
||||
render_mode,
|
||||
..info.font.clone()
|
||||
},
|
||||
offset: info.offset + shadow.offset,
|
||||
glyph_range: info.glyph_range,
|
||||
glyph_keys: info.glyph_keys.clone(),
|
||||
glyph_gpu_blocks: Vec::new(),
|
||||
shadow: true,
|
||||
glyph_raster_space: info.glyph_raster_space,
|
||||
})
|
||||
PrimitiveContainer::TextRun(TextRunPrimitiveCpu::new(
|
||||
font,
|
||||
info.offset + shadow.offset,
|
||||
info.glyph_range,
|
||||
info.glyph_keys.clone(),
|
||||
true,
|
||||
info.glyph_raster_space,
|
||||
))
|
||||
}
|
||||
PrimitiveContainer::Brush(ref brush) => {
|
||||
match brush.kind {
|
||||
@ -1401,6 +1438,84 @@ impl PrimitiveStore {
|
||||
self.cpu_metadata.len()
|
||||
}
|
||||
|
||||
fn build_prim_segments_if_needed(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
pic_state: &mut PictureState,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
frame_context: &FrameBuildingContext,
|
||||
) {
|
||||
let metadata = &self.cpu_metadata[prim_index.0];
|
||||
|
||||
if metadata.prim_kind != PrimitiveKind::Brush {
|
||||
return;
|
||||
}
|
||||
|
||||
let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0];
|
||||
|
||||
if let BrushKind::Border { ref mut source, .. } = brush.kind {
|
||||
if let BorderSource::Border {
|
||||
ref border,
|
||||
ref mut cache_key,
|
||||
ref widths,
|
||||
ref mut handle,
|
||||
ref mut task_info,
|
||||
..
|
||||
} = *source {
|
||||
// TODO(gw): When drawing in screen raster mode, we should also incorporate a
|
||||
// scale factor from the world transform to get an appropriately
|
||||
// sized border task.
|
||||
let world_scale = LayoutToWorldScale::new(1.0);
|
||||
let scale = world_scale * frame_context.device_pixel_scale;
|
||||
let scale_au = Au::from_f32_px(scale.0);
|
||||
let needs_update = scale_au != cache_key.scale;
|
||||
|
||||
if needs_update {
|
||||
cache_key.scale = scale_au;
|
||||
|
||||
*task_info = Some(BorderRenderTaskInfo::new(
|
||||
&metadata.local_rect,
|
||||
border,
|
||||
widths,
|
||||
scale,
|
||||
));
|
||||
}
|
||||
|
||||
let task_info = task_info.as_ref().unwrap();
|
||||
|
||||
*handle = Some(frame_state.resource_cache.request_render_task(
|
||||
RenderTaskCacheKey {
|
||||
size: DeviceIntSize::zero(),
|
||||
kind: RenderTaskCacheKeyKind::Border(cache_key.clone()),
|
||||
},
|
||||
frame_state.gpu_cache,
|
||||
frame_state.render_tasks,
|
||||
None,
|
||||
false, // todo
|
||||
|render_tasks| {
|
||||
let task = RenderTask::new_border(
|
||||
task_info.size,
|
||||
task_info.instances.clone(),
|
||||
);
|
||||
|
||||
let task_id = render_tasks.add(task);
|
||||
|
||||
pic_state.tasks.push(task_id);
|
||||
|
||||
task_id
|
||||
}
|
||||
));
|
||||
|
||||
if needs_update {
|
||||
brush.segment_desc = Some(BrushSegmentDescriptor {
|
||||
segments: task_info.segments.clone(),
|
||||
clip_mask_kind: BrushClipMaskKind::Unknown,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_prim_for_render_inner(
|
||||
&mut self,
|
||||
prim_index: PrimitiveIndex,
|
||||
@ -1663,21 +1778,29 @@ impl PrimitiveStore {
|
||||
);
|
||||
}
|
||||
}
|
||||
BrushKind::Border { request, .. } => {
|
||||
let image_properties = frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(request.key);
|
||||
BrushKind::Border { ref mut source, .. } => {
|
||||
match *source {
|
||||
BorderSource::Image(request) => {
|
||||
let image_properties = frame_state
|
||||
.resource_cache
|
||||
.get_image_properties(request.key);
|
||||
|
||||
if let Some(image_properties) = image_properties {
|
||||
// Update opacity for this primitive to ensure the correct
|
||||
// batching parameters are used.
|
||||
metadata.opacity.is_opaque =
|
||||
image_properties.descriptor.is_opaque;
|
||||
if let Some(image_properties) = image_properties {
|
||||
// Update opacity for this primitive to ensure the correct
|
||||
// batching parameters are used.
|
||||
metadata.opacity.is_opaque =
|
||||
image_properties.descriptor.is_opaque;
|
||||
|
||||
frame_state.resource_cache.request_image(
|
||||
request,
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
frame_state.resource_cache.request_image(
|
||||
request,
|
||||
frame_state.gpu_cache,
|
||||
);
|
||||
}
|
||||
}
|
||||
BorderSource::Border { .. } => {
|
||||
// Handled earlier since we need to update the segment
|
||||
// descriptor *before* update_clip_task() is called.
|
||||
}
|
||||
}
|
||||
}
|
||||
BrushKind::RadialGradient {
|
||||
@ -2004,8 +2127,7 @@ impl PrimitiveStore {
|
||||
segment_builder.build(|segment| {
|
||||
segments.push(
|
||||
BrushSegment::new(
|
||||
segment.rect.origin,
|
||||
segment.rect.size,
|
||||
segment.rect,
|
||||
segment.has_mask,
|
||||
segment.edge_flags,
|
||||
[0.0; 4],
|
||||
@ -2390,6 +2512,13 @@ impl PrimitiveStore {
|
||||
(local_rect, unclipped)
|
||||
};
|
||||
|
||||
self.build_prim_segments_if_needed(
|
||||
prim_index,
|
||||
pic_state,
|
||||
frame_state,
|
||||
frame_context,
|
||||
);
|
||||
|
||||
if may_need_clip_mask && !self.update_clip_task(
|
||||
prim_index,
|
||||
prim_run_context,
|
||||
|
@ -813,11 +813,11 @@ impl RenderBackend {
|
||||
self.resource_cache
|
||||
.update_resources(updates, &mut profile_counters.resources);
|
||||
}
|
||||
ApiMsg::GetGlyphDimensions(instance_key, glyph_keys, tx) => {
|
||||
let mut glyph_dimensions = Vec::with_capacity(glyph_keys.len());
|
||||
ApiMsg::GetGlyphDimensions(instance_key, glyph_indices, tx) => {
|
||||
let mut glyph_dimensions = Vec::with_capacity(glyph_indices.len());
|
||||
if let Some(font) = self.resource_cache.get_font_instance(instance_key) {
|
||||
for glyph_key in &glyph_keys {
|
||||
let glyph_dim = self.resource_cache.get_glyph_dimensions(&font, glyph_key);
|
||||
for glyph_index in &glyph_indices {
|
||||
let glyph_dim = self.resource_cache.get_glyph_dimensions(&font, *glyph_index);
|
||||
glyph_dimensions.push(glyph_dim);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, DeviceIntSideOffsets, ImageDescriptor, ImageFormat};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use api::FontRenderMode;
|
||||
use border::BorderCacheKey;
|
||||
use box_shadow::{BoxShadowCacheKey};
|
||||
use clip::{ClipSource, ClipStore, ClipWorkItem};
|
||||
use clip_scroll_tree::CoordinateSystemId;
|
||||
@ -14,7 +15,7 @@ use euclid::{TypedPoint2D, TypedVector2D};
|
||||
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
|
||||
use glyph_rasterizer::GpuGlyphCacheKey;
|
||||
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||
use gpu_types::{ImageSource, RasterizationSpace, UvRectKind};
|
||||
use gpu_types::{BorderInstance, ImageSource, RasterizationSpace, UvRectKind};
|
||||
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use pathfinder_partitioner::mesh::Mesh;
|
||||
@ -249,6 +250,13 @@ pub enum BlitSource {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BorderTask {
|
||||
pub instances: Vec<BorderInstance>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
@ -278,6 +286,7 @@ pub enum RenderTaskKind {
|
||||
Readback(DeviceIntRect),
|
||||
Scaling(RenderTargetKind),
|
||||
Blit(BlitTask),
|
||||
Border(BorderTask),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
@ -557,6 +566,21 @@ impl RenderTask {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_border(
|
||||
size: DeviceIntSize,
|
||||
instances: Vec<BorderInstance>,
|
||||
) -> Self {
|
||||
RenderTask {
|
||||
children: Vec::new(),
|
||||
location: RenderTaskLocation::Dynamic(None, Some(size)),
|
||||
kind: RenderTaskKind::Border(BorderTask {
|
||||
instances,
|
||||
}),
|
||||
clear_mode: ClearMode::Transparent,
|
||||
saved_index: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_scaling(
|
||||
target_kind: RenderTargetKind,
|
||||
src_task_id: RenderTaskId,
|
||||
@ -616,6 +640,7 @@ impl RenderTask {
|
||||
|
||||
RenderTaskKind::ClipRegion(..) |
|
||||
RenderTaskKind::Glyph(_) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::Blit(..) => {
|
||||
UvRectKind::Rect
|
||||
}
|
||||
@ -670,6 +695,7 @@ impl RenderTask {
|
||||
}
|
||||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::Scaling(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::Blit(..) => {
|
||||
[0.0; 3]
|
||||
}
|
||||
@ -704,6 +730,7 @@ impl RenderTask {
|
||||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::Scaling(..) |
|
||||
RenderTaskKind::Blit(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::CacheMask(..) |
|
||||
RenderTaskKind::Glyph(..) => {
|
||||
panic!("texture handle not supported for this task kind");
|
||||
@ -776,6 +803,7 @@ impl RenderTask {
|
||||
target_kind
|
||||
}
|
||||
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::Picture(..) => {
|
||||
RenderTargetKind::Color
|
||||
}
|
||||
@ -801,6 +829,7 @@ impl RenderTask {
|
||||
RenderTaskKind::Scaling(..) |
|
||||
RenderTaskKind::ClipRegion(..) |
|
||||
RenderTaskKind::Blit(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::Glyph(..) => false,
|
||||
|
||||
// TODO(gw): For now, we've disabled the shared clip mask
|
||||
@ -837,6 +866,7 @@ impl RenderTask {
|
||||
RenderTaskKind::Scaling(..) |
|
||||
RenderTaskKind::Blit(..) |
|
||||
RenderTaskKind::ClipRegion(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::CacheMask(..) |
|
||||
RenderTaskKind::Glyph(..) => {
|
||||
return;
|
||||
@ -887,6 +917,9 @@ impl RenderTask {
|
||||
pt.new_level("Scaling".to_owned());
|
||||
pt.add_item(format!("kind: {:?}", kind));
|
||||
}
|
||||
RenderTaskKind::Border(..) => {
|
||||
pt.new_level("Border".to_owned());
|
||||
}
|
||||
RenderTaskKind::Blit(ref task) => {
|
||||
pt.new_level("Blit".to_owned());
|
||||
pt.add_item(format!("source: {:?}", task.source));
|
||||
@ -931,6 +964,7 @@ pub enum RenderTaskCacheKeyKind {
|
||||
#[allow(dead_code)]
|
||||
Glyph(GpuGlyphCacheKey),
|
||||
Picture(PictureCacheKey),
|
||||
Border(BorderCacheKey),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
|
||||
|
@ -128,6 +128,10 @@ const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag {
|
||||
label: "C_Clip",
|
||||
color: debug_colors::PURPLE,
|
||||
};
|
||||
const GPU_TAG_CACHE_BORDER: GpuProfileTag = GpuProfileTag {
|
||||
label: "C_Border",
|
||||
color: debug_colors::CORNSILK,
|
||||
};
|
||||
const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag {
|
||||
label: "target init",
|
||||
color: debug_colors::SLATEGREY,
|
||||
@ -390,6 +394,53 @@ pub(crate) mod desc {
|
||||
],
|
||||
};
|
||||
|
||||
pub const BORDER: VertexDescriptor = VertexDescriptor {
|
||||
vertex_attributes: &[
|
||||
VertexAttribute {
|
||||
name: "aPosition",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
],
|
||||
instance_attributes: &[
|
||||
VertexAttribute {
|
||||
name: "aTaskOrigin",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aRect",
|
||||
count: 4,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aColor0",
|
||||
count: 4,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aColor1",
|
||||
count: 4,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aFlags",
|
||||
count: 1,
|
||||
kind: VertexAttributeKind::I32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aWidths",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
VertexAttribute {
|
||||
name: "aRadii",
|
||||
count: 2,
|
||||
kind: VertexAttributeKind::F32,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
pub const CLIP: VertexDescriptor = VertexDescriptor {
|
||||
vertex_attributes: &[
|
||||
VertexAttribute {
|
||||
@ -573,6 +624,7 @@ pub(crate) enum VertexArrayKind {
|
||||
DashAndDot,
|
||||
VectorStencil,
|
||||
VectorCover,
|
||||
Border,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
@ -1293,6 +1345,7 @@ pub struct RendererVAOs {
|
||||
blur_vao: VAO,
|
||||
clip_vao: VAO,
|
||||
dash_and_dot_vao: VAO,
|
||||
border_vao: VAO,
|
||||
}
|
||||
|
||||
/// The renderer is responsible for submitting to the GPU the work prepared by the
|
||||
@ -1579,6 +1632,8 @@ impl Renderer {
|
||||
|
||||
let blur_vao = device.create_vao_with_new_instances(&desc::BLUR, &prim_vao);
|
||||
let clip_vao = device.create_vao_with_new_instances(&desc::CLIP, &prim_vao);
|
||||
let border_vao =
|
||||
device.create_vao_with_new_instances(&desc::BORDER, &prim_vao);
|
||||
let dash_and_dot_vao =
|
||||
device.create_vao_with_new_instances(&desc::BORDER_CORNER_DASH_AND_DOT, &prim_vao);
|
||||
let texture_cache_upload_pbo = device.create_pbo();
|
||||
@ -1734,6 +1789,7 @@ impl Renderer {
|
||||
blur_vao,
|
||||
clip_vao,
|
||||
dash_and_dot_vao,
|
||||
border_vao,
|
||||
},
|
||||
node_data_texture,
|
||||
local_clip_rects_texture,
|
||||
@ -3248,9 +3304,36 @@ impl Renderer {
|
||||
self.device.disable_depth_write();
|
||||
self.device.set_blend(false);
|
||||
|
||||
for rect in &target.clears {
|
||||
self.device.clear_target(Some([0.0, 0.0, 0.0, 0.0]), None, Some(*rect));
|
||||
}
|
||||
|
||||
// Handle any blits to this texture from child tasks.
|
||||
self.handle_blits(&target.blits, render_tasks);
|
||||
|
||||
// Draw any borders for this target.
|
||||
if !target.border_segments.is_empty() {
|
||||
let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_BORDER);
|
||||
|
||||
self.device.set_blend(true);
|
||||
self.device.set_blend_mode_premultiplied_alpha();
|
||||
|
||||
self.shaders.cs_border_segment.bind(
|
||||
&mut self.device,
|
||||
&projection,
|
||||
&mut self.renderer_errors,
|
||||
);
|
||||
|
||||
self.draw_instanced_batch(
|
||||
&target.border_segments,
|
||||
VertexArrayKind::Border,
|
||||
&BatchTextures::no_texture(),
|
||||
stats,
|
||||
);
|
||||
|
||||
self.device.set_blend(false);
|
||||
}
|
||||
|
||||
// Draw any blurs for this target.
|
||||
if !target.horizontal_blurs.is_empty() {
|
||||
let _timer = self.gpu_profile.start_timer(GPU_TAG_BLUR);
|
||||
@ -3853,6 +3936,7 @@ impl Renderer {
|
||||
self.device.delete_vao(self.vaos.clip_vao);
|
||||
self.device.delete_vao(self.vaos.blur_vao);
|
||||
self.device.delete_vao(self.vaos.dash_and_dot_vao);
|
||||
self.device.delete_vao(self.vaos.border_vao);
|
||||
|
||||
#[cfg(feature = "debug_renderer")]
|
||||
{
|
||||
@ -4448,6 +4532,7 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
|
||||
VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao,
|
||||
VertexArrayKind::VectorStencil => &gpu_glyph_renderer.vector_stencil_vao,
|
||||
VertexArrayKind::VectorCover => &gpu_glyph_renderer.vector_cover_vao,
|
||||
VertexArrayKind::Border => &vaos.border_vao,
|
||||
}
|
||||
}
|
||||
|
||||
@ -4462,5 +4547,6 @@ fn get_vao<'a>(vertex_array_kind: VertexArrayKind,
|
||||
VertexArrayKind::Blur => &vaos.blur_vao,
|
||||
VertexArrayKind::DashAndDot => &vaos.dash_and_dot_vao,
|
||||
VertexArrayKind::VectorStencil | VertexArrayKind::VectorCover => unreachable!(),
|
||||
VertexArrayKind::Border => &vaos.border_vao,
|
||||
}
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
* 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 api::{AddFont, BlobImageResources, ResourceUpdate, ResourceUpdates};
|
||||
use api::{AddFont, BlobImageResources, ResourceUpdate};
|
||||
use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest};
|
||||
use api::{ClearCache, ColorF, DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
|
||||
use api::{Epoch, FontInstanceKey, FontKey, FontTemplate};
|
||||
use api::{Epoch, FontInstanceKey, FontKey, FontTemplate, GlyphIndex};
|
||||
use api::{ExternalImageData, ExternalImageType};
|
||||
use api::{FontInstanceOptions, FontInstancePlatformOptions, FontVariation};
|
||||
use api::{GlyphDimensions, GlyphKey, IdNamespace};
|
||||
use api::{GlyphDimensions, IdNamespace};
|
||||
use api::{ImageData, ImageDescriptor, ImageKey, ImageRendering};
|
||||
use api::{TileOffset, TileSize};
|
||||
use app_units::Au;
|
||||
@ -23,7 +23,7 @@ use euclid::size2;
|
||||
use glyph_cache::GlyphCache;
|
||||
#[cfg(not(feature = "pathfinder"))]
|
||||
use glyph_cache::GlyphCacheEntry;
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphRasterizer, GlyphRequest};
|
||||
use glyph_rasterizer::{FontInstance, GlyphFormat, GlyphKey, GlyphRasterizer};
|
||||
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle};
|
||||
use gpu_types::UvRectKind;
|
||||
use internal_types::{FastHashMap, FastHashSet, SourceTexture, TextureUpdateList};
|
||||
@ -174,7 +174,7 @@ where
|
||||
K: Clone + Hash + Eq + Debug,
|
||||
U: Default,
|
||||
{
|
||||
pub fn new() -> ResourceClassCache<K, V, U> {
|
||||
pub fn new() -> Self {
|
||||
ResourceClassCache {
|
||||
resources: FastHashMap::default(),
|
||||
user_data: Default::default(),
|
||||
@ -282,7 +282,7 @@ impl BlobImageResources for Resources {
|
||||
}
|
||||
}
|
||||
|
||||
pub type GlyphDimensionsCache = FastHashMap<GlyphRequest, Option<GlyphDimensions>>;
|
||||
pub type GlyphDimensionsCache = FastHashMap<(FontInstance, GlyphIndex), Option<GlyphDimensions>>;
|
||||
|
||||
pub struct ResourceCache {
|
||||
cached_glyphs: GlyphCache,
|
||||
@ -371,14 +371,14 @@ impl ResourceCache {
|
||||
|
||||
pub fn update_resources(
|
||||
&mut self,
|
||||
updates: ResourceUpdates,
|
||||
updates: Vec<ResourceUpdate>,
|
||||
profile_counters: &mut ResourceProfileCounters,
|
||||
) {
|
||||
// TODO, there is potential for optimization here, by processing updates in
|
||||
// bulk rather than one by one (for example by sorting allocations by size or
|
||||
// in a way that reduces fragmentation in the atlas).
|
||||
|
||||
for update in updates.updates {
|
||||
for update in updates {
|
||||
match update {
|
||||
ResourceUpdate::AddImage(img) => {
|
||||
if let ImageData::Raw(ref bytes) = img.data {
|
||||
@ -449,7 +449,6 @@ impl ResourceCache {
|
||||
) {
|
||||
let FontInstanceOptions {
|
||||
render_mode,
|
||||
subpx_dir,
|
||||
flags,
|
||||
bg_color,
|
||||
..
|
||||
@ -460,7 +459,6 @@ impl ResourceCache {
|
||||
ColorF::new(0.0, 0.0, 0.0, 1.0),
|
||||
bg_color,
|
||||
render_mode,
|
||||
subpx_dir,
|
||||
flags,
|
||||
platform_options,
|
||||
variations,
|
||||
@ -510,16 +508,14 @@ impl ResourceCache {
|
||||
tiling,
|
||||
);
|
||||
}
|
||||
let dirty_rect = Some(descriptor.full_rect());
|
||||
|
||||
let resource = ImageResource {
|
||||
descriptor,
|
||||
data,
|
||||
epoch: Epoch(0),
|
||||
tiling,
|
||||
dirty_rect: Some(DeviceUintRect::new(
|
||||
DeviceUintPoint::zero(),
|
||||
descriptor.size,
|
||||
)),
|
||||
dirty_rect,
|
||||
};
|
||||
|
||||
self.resources.image_templates.insert(image_key, resource);
|
||||
@ -636,9 +632,14 @@ impl ResourceCache {
|
||||
let needs_upload = self.texture_cache
|
||||
.request(&entry.as_ref().unwrap().texture_cache_handle, gpu_cache);
|
||||
|
||||
if !needs_upload && !needs_update {
|
||||
return;
|
||||
}
|
||||
let dirty_rect = if needs_upload {
|
||||
// the texture cache entry has been evicted, treat it as all dirty
|
||||
Some(template.descriptor.full_rect())
|
||||
} else if needs_update {
|
||||
template.dirty_rect
|
||||
} else {
|
||||
return
|
||||
};
|
||||
|
||||
// We can start a worker thread rasterizing right now, if:
|
||||
// - The image is a blob.
|
||||
@ -658,7 +659,7 @@ impl ResourceCache {
|
||||
tile_offset.y as f32 * tile_size as f32,
|
||||
);
|
||||
|
||||
if let Some(dirty) = template.dirty_rect {
|
||||
if let Some(dirty) = dirty_rect {
|
||||
if intersect_for_tile(dirty, actual_size, tile_size, tile_offset).is_none() {
|
||||
// don't bother requesting unchanged tiles
|
||||
return
|
||||
@ -678,7 +679,7 @@ impl ResourceCache {
|
||||
offset,
|
||||
format: template.descriptor.format,
|
||||
},
|
||||
template.dirty_rect,
|
||||
dirty_rect,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -812,15 +813,13 @@ impl ResourceCache {
|
||||
pub fn get_glyph_dimensions(
|
||||
&mut self,
|
||||
font: &FontInstance,
|
||||
key: &GlyphKey,
|
||||
glyph_index: GlyphIndex,
|
||||
) -> Option<GlyphDimensions> {
|
||||
let key = GlyphRequest::new(font, key);
|
||||
|
||||
match self.cached_glyph_dimensions.entry(key.clone()) {
|
||||
match self.cached_glyph_dimensions.entry((font.clone(), glyph_index)) {
|
||||
Occupied(entry) => *entry.get(),
|
||||
Vacant(entry) => *entry.insert(
|
||||
self.glyph_rasterizer
|
||||
.get_glyph_dimensions(&key.font, &key.key),
|
||||
.get_glyph_dimensions(font, glyph_index),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +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 api::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdates};
|
||||
use api::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdate};
|
||||
use api::channel::MsgSender;
|
||||
use display_list_flattener::build_scene;
|
||||
use frame_builder::{FrameBuilderConfig, FrameBuilder};
|
||||
@ -19,7 +19,7 @@ pub enum SceneBuilderRequest {
|
||||
Transaction {
|
||||
document_id: DocumentId,
|
||||
scene: Option<SceneRequest>,
|
||||
resource_updates: ResourceUpdates,
|
||||
resource_updates: Vec<ResourceUpdate>,
|
||||
frame_ops: Vec<FrameMsg>,
|
||||
render: bool,
|
||||
},
|
||||
@ -33,7 +33,7 @@ pub enum SceneBuilderResult {
|
||||
Transaction {
|
||||
document_id: DocumentId,
|
||||
built_scene: Option<BuiltScene>,
|
||||
resource_updates: ResourceUpdates,
|
||||
resource_updates: Vec<ResourceUpdate>,
|
||||
frame_ops: Vec<FrameMsg>,
|
||||
render: bool,
|
||||
result_tx: Option<Sender<SceneSwapResult>>,
|
||||
|
@ -403,6 +403,7 @@ fn create_prim_shader(
|
||||
VertexArrayKind::DashAndDot => desc::BORDER_CORNER_DASH_AND_DOT,
|
||||
VertexArrayKind::VectorStencil => desc::VECTOR_STENCIL,
|
||||
VertexArrayKind::VectorCover => desc::VECTOR_COVER,
|
||||
VertexArrayKind::Border => desc::BORDER,
|
||||
};
|
||||
|
||||
let program = device.create_program(name, &prefix, &vertex_descriptor);
|
||||
@ -464,6 +465,7 @@ pub struct Shaders {
|
||||
// of these shaders are then used by the primitive shaders.
|
||||
pub cs_blur_a8: LazilyCompiledShader,
|
||||
pub cs_blur_rgba8: LazilyCompiledShader,
|
||||
pub cs_border_segment: LazilyCompiledShader,
|
||||
|
||||
// Brush shaders
|
||||
brush_solid: BrushShader,
|
||||
@ -711,6 +713,14 @@ impl Shaders {
|
||||
options.precache_shaders,
|
||||
)?;
|
||||
|
||||
let cs_border_segment = LazilyCompiledShader::new(
|
||||
ShaderKind::Cache(VertexArrayKind::Border),
|
||||
"cs_border_segment",
|
||||
&[],
|
||||
device,
|
||||
options.precache_shaders,
|
||||
)?;
|
||||
|
||||
let ps_split_composite = LazilyCompiledShader::new(
|
||||
ShaderKind::Primitive,
|
||||
"ps_split_composite",
|
||||
@ -726,6 +736,7 @@ impl Shaders {
|
||||
Ok(Shaders {
|
||||
cs_blur_a8,
|
||||
cs_blur_rgba8,
|
||||
cs_border_segment,
|
||||
brush_solid,
|
||||
brush_image,
|
||||
brush_blend,
|
||||
@ -844,6 +855,7 @@ impl Shaders {
|
||||
}
|
||||
self.ps_border_corner.deinit(device);
|
||||
self.ps_border_edge.deinit(device);
|
||||
self.cs_border_segment.deinit(device);
|
||||
self.ps_split_composite.deinit(device);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use device::{FrameId, Texture};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use euclid::{TypedPoint2D, TypedVector2D};
|
||||
use gpu_cache::{GpuCache};
|
||||
use gpu_types::{BlurDirection, BlurInstance};
|
||||
use gpu_types::{BorderInstance, BlurDirection, BlurInstance};
|
||||
use gpu_types::{ClipScrollNodeData, ZBufferIdGenerator};
|
||||
use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture};
|
||||
#[cfg(feature = "pathfinder")]
|
||||
@ -23,7 +23,7 @@ use profiler::FrameProfileCounters;
|
||||
use render_task::{BlitSource, RenderTaskAddress, RenderTaskId, RenderTaskKind};
|
||||
use render_task::{BlurTask, ClearMode, GlyphTask, RenderTaskLocation, RenderTaskTree};
|
||||
use resource_cache::ResourceCache;
|
||||
use std::{cmp, usize, f32, i32};
|
||||
use std::{cmp, usize, f32, i32, mem};
|
||||
use texture_allocator::GuillotineAllocator;
|
||||
#[cfg(feature = "pathfinder")]
|
||||
use webrender_api::{DevicePixel, FontRenderMode};
|
||||
@ -433,6 +433,7 @@ impl RenderTarget for ColorRenderTarget {
|
||||
}
|
||||
}
|
||||
RenderTaskKind::ClipRegion(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::CacheMask(..) => {
|
||||
panic!("Should not be added to color target!");
|
||||
}
|
||||
@ -565,6 +566,7 @@ impl RenderTarget for AlphaRenderTarget {
|
||||
RenderTaskKind::Readback(..) |
|
||||
RenderTaskKind::Picture(..) |
|
||||
RenderTaskKind::Blit(..) |
|
||||
RenderTaskKind::Border(..) |
|
||||
RenderTaskKind::Glyph(..) => {
|
||||
panic!("BUG: should not be added to alpha target!");
|
||||
}
|
||||
@ -627,6 +629,8 @@ pub struct TextureCacheRenderTarget {
|
||||
pub horizontal_blurs: Vec<BlurInstance>,
|
||||
pub blits: Vec<BlitJob>,
|
||||
pub glyphs: Vec<GlyphJob>,
|
||||
pub border_segments: Vec<BorderInstance>,
|
||||
pub clears: Vec<DeviceIntRect>,
|
||||
}
|
||||
|
||||
impl TextureCacheRenderTarget {
|
||||
@ -636,6 +640,8 @@ impl TextureCacheRenderTarget {
|
||||
horizontal_blurs: vec![],
|
||||
blits: vec![],
|
||||
glyphs: vec![],
|
||||
border_segments: vec![],
|
||||
clears: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,6 +684,20 @@ impl TextureCacheRenderTarget {
|
||||
}
|
||||
}
|
||||
}
|
||||
RenderTaskKind::Border(ref mut task_info) => {
|
||||
self.clears.push(target_rect.0);
|
||||
|
||||
// TODO(gw): It may be better to store the task origin in
|
||||
// the render task data instead of per instance.
|
||||
let task_origin = target_rect.0.origin.to_f32();
|
||||
for instance in &mut task_info.instances {
|
||||
instance.task_origin = task_origin;
|
||||
}
|
||||
|
||||
let instances = mem::replace(&mut task_info.instances, Vec::new());
|
||||
|
||||
self.border_segments.extend(instances);
|
||||
}
|
||||
RenderTaskKind::Glyph(ref mut task_info) => {
|
||||
self.add_glyph_task(task_info, target_rect.0)
|
||||
}
|
||||
|
@ -18,8 +18,8 @@ bitflags = "1.0"
|
||||
byteorder = "1.2.1"
|
||||
ipc-channel = {version = "0.10.0", optional = true}
|
||||
euclid = { version = "0.17", features = ["serde"] }
|
||||
serde = { version = "=1.0.37", features = ["rc"] }
|
||||
serde_derive = { version = "=1.0.37", features = ["deserialize_in_place"] }
|
||||
serde = { version = "=1.0.58", features = ["rc"] }
|
||||
serde_derive = { version = "=1.0.58", features = ["deserialize_in_place"] }
|
||||
serde_bytes = "0.10"
|
||||
time = "0.1"
|
||||
|
||||
|
@ -13,7 +13,7 @@ use std::path::PathBuf;
|
||||
use std::u32;
|
||||
use {BuiltDisplayList, BuiltDisplayListDescriptor, ColorF, DeviceIntPoint, DeviceUintRect};
|
||||
use {DeviceUintSize, ExternalScrollId, FontInstanceKey, FontInstanceOptions};
|
||||
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphKey, ImageData};
|
||||
use {FontInstancePlatformOptions, FontKey, FontVariation, GlyphDimensions, GlyphIndex, ImageData};
|
||||
use {ImageDescriptor, ImageKey, ItemTag, LayoutPoint, LayoutSize, LayoutTransform, LayoutVector2D};
|
||||
use {NativeFontHandle, WorldPoint};
|
||||
|
||||
@ -21,12 +21,6 @@ pub type TileSize = u16;
|
||||
/// Documents are rendered in the ascending order of their associated layer values.
|
||||
pub type DocumentLayer = i8;
|
||||
|
||||
/// The resource updates for a given transaction (they must be applied in the same frame).
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub struct ResourceUpdates {
|
||||
pub updates: Vec<ResourceUpdate>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum ResourceUpdate {
|
||||
AddImage(AddImage),
|
||||
@ -38,94 +32,6 @@ pub enum ResourceUpdate {
|
||||
DeleteFontInstance(FontInstanceKey),
|
||||
}
|
||||
|
||||
impl ResourceUpdates {
|
||||
pub fn new() -> Self {
|
||||
ResourceUpdates {
|
||||
updates: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: ImageData,
|
||||
tiling: Option<TileSize>,
|
||||
) {
|
||||
self.updates.push(ResourceUpdate::AddImage(AddImage {
|
||||
key,
|
||||
descriptor,
|
||||
data,
|
||||
tiling,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn update_image(
|
||||
&mut self,
|
||||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: ImageData,
|
||||
dirty_rect: Option<DeviceUintRect>,
|
||||
) {
|
||||
self.updates.push(ResourceUpdate::UpdateImage(UpdateImage {
|
||||
key,
|
||||
descriptor,
|
||||
data,
|
||||
dirty_rect,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn delete_image(&mut self, key: ImageKey) {
|
||||
self.updates.push(ResourceUpdate::DeleteImage(key));
|
||||
}
|
||||
|
||||
pub fn add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32) {
|
||||
self.updates
|
||||
.push(ResourceUpdate::AddFont(AddFont::Raw(key, bytes, index)));
|
||||
}
|
||||
|
||||
pub fn add_native_font(&mut self, key: FontKey, native_handle: NativeFontHandle) {
|
||||
self.updates
|
||||
.push(ResourceUpdate::AddFont(AddFont::Native(key, native_handle)));
|
||||
}
|
||||
|
||||
pub fn delete_font(&mut self, key: FontKey) {
|
||||
self.updates.push(ResourceUpdate::DeleteFont(key));
|
||||
}
|
||||
|
||||
pub fn add_font_instance(
|
||||
&mut self,
|
||||
key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
glyph_size: Au,
|
||||
options: Option<FontInstanceOptions>,
|
||||
platform_options: Option<FontInstancePlatformOptions>,
|
||||
variations: Vec<FontVariation>,
|
||||
) {
|
||||
self.updates
|
||||
.push(ResourceUpdate::AddFontInstance(AddFontInstance {
|
||||
key,
|
||||
font_key,
|
||||
glyph_size,
|
||||
options,
|
||||
platform_options,
|
||||
variations,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
|
||||
self.updates.push(ResourceUpdate::DeleteFontInstance(key));
|
||||
}
|
||||
|
||||
pub fn merge(&mut self, mut other: ResourceUpdates) {
|
||||
self.updates.append(&mut other.updates);
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.updates.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/// A Transaction is a group of commands to apply atomically to a document.
|
||||
///
|
||||
/// This mechanism ensures that:
|
||||
@ -142,7 +48,7 @@ pub struct Transaction {
|
||||
payloads: Vec<Payload>,
|
||||
|
||||
// Resource updates are applied after scene building.
|
||||
resource_updates: ResourceUpdates,
|
||||
pub resource_updates: Vec<ResourceUpdate>,
|
||||
|
||||
// If true the transaction is piped through the scene building thread, if false
|
||||
// it will be applied directly on the render backend.
|
||||
@ -156,7 +62,7 @@ impl Transaction {
|
||||
Transaction {
|
||||
scene_ops: Vec::new(),
|
||||
frame_ops: Vec::new(),
|
||||
resource_updates: ResourceUpdates::new(),
|
||||
resource_updates: Vec::new(),
|
||||
payloads: Vec::new(),
|
||||
use_scene_builder_thread: false, // TODO: make this true by default.
|
||||
generate_frame: false,
|
||||
@ -178,7 +84,7 @@ impl Transaction {
|
||||
!self.generate_frame &&
|
||||
self.scene_ops.is_empty() &&
|
||||
self.frame_ops.is_empty() &&
|
||||
self.resource_updates.updates.is_empty()
|
||||
self.resource_updates.is_empty()
|
||||
}
|
||||
|
||||
pub fn update_epoch(&mut self, pipeline_id: PipelineId, epoch: Epoch) {
|
||||
@ -257,8 +163,8 @@ impl Transaction {
|
||||
self.payloads.push(Payload { epoch, pipeline_id, display_list_data });
|
||||
}
|
||||
|
||||
pub fn update_resources(&mut self, resources: ResourceUpdates) {
|
||||
self.resource_updates.merge(resources);
|
||||
pub fn update_resources(&mut self, resources: Vec<ResourceUpdate>) {
|
||||
self.merge(resources);
|
||||
}
|
||||
|
||||
pub fn set_window_parameters(
|
||||
@ -353,6 +259,86 @@ impl Transaction {
|
||||
self.payloads,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_image(
|
||||
&mut self,
|
||||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: ImageData,
|
||||
tiling: Option<TileSize>,
|
||||
) {
|
||||
self.resource_updates.push(ResourceUpdate::AddImage(AddImage {
|
||||
key,
|
||||
descriptor,
|
||||
data,
|
||||
tiling,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn update_image(
|
||||
&mut self,
|
||||
key: ImageKey,
|
||||
descriptor: ImageDescriptor,
|
||||
data: ImageData,
|
||||
dirty_rect: Option<DeviceUintRect>,
|
||||
) {
|
||||
self.resource_updates.push(ResourceUpdate::UpdateImage(UpdateImage {
|
||||
key,
|
||||
descriptor,
|
||||
data,
|
||||
dirty_rect,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn delete_image(&mut self, key: ImageKey) {
|
||||
self.resource_updates.push(ResourceUpdate::DeleteImage(key));
|
||||
}
|
||||
|
||||
pub fn add_raw_font(&mut self, key: FontKey, bytes: Vec<u8>, index: u32) {
|
||||
self.resource_updates
|
||||
.push(ResourceUpdate::AddFont(AddFont::Raw(key, bytes, index)));
|
||||
}
|
||||
|
||||
pub fn add_native_font(&mut self, key: FontKey, native_handle: NativeFontHandle) {
|
||||
self.resource_updates
|
||||
.push(ResourceUpdate::AddFont(AddFont::Native(key, native_handle)));
|
||||
}
|
||||
|
||||
pub fn delete_font(&mut self, key: FontKey) {
|
||||
self.resource_updates.push(ResourceUpdate::DeleteFont(key));
|
||||
}
|
||||
|
||||
pub fn add_font_instance(
|
||||
&mut self,
|
||||
key: FontInstanceKey,
|
||||
font_key: FontKey,
|
||||
glyph_size: Au,
|
||||
options: Option<FontInstanceOptions>,
|
||||
platform_options: Option<FontInstancePlatformOptions>,
|
||||
variations: Vec<FontVariation>,
|
||||
) {
|
||||
self.resource_updates
|
||||
.push(ResourceUpdate::AddFontInstance(AddFontInstance {
|
||||
key,
|
||||
font_key,
|
||||
glyph_size,
|
||||
options,
|
||||
platform_options,
|
||||
variations,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
|
||||
self.resource_updates.push(ResourceUpdate::DeleteFontInstance(key));
|
||||
}
|
||||
|
||||
pub fn merge(&mut self, mut other: Vec<ResourceUpdate>) {
|
||||
self.resource_updates.append(&mut other);
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
self.resource_updates.clear()
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a transaction in the format sent through the channel.
|
||||
@ -360,7 +346,7 @@ impl Transaction {
|
||||
pub struct TransactionMsg {
|
||||
pub scene_ops: Vec<SceneMsg>,
|
||||
pub frame_ops: Vec<FrameMsg>,
|
||||
pub resource_updates: ResourceUpdates,
|
||||
pub resource_updates: Vec<ResourceUpdate>,
|
||||
pub generate_frame: bool,
|
||||
pub use_scene_builder_thread: bool,
|
||||
}
|
||||
@ -370,7 +356,7 @@ impl TransactionMsg {
|
||||
!self.generate_frame &&
|
||||
self.scene_ops.is_empty() &&
|
||||
self.frame_ops.is_empty() &&
|
||||
self.resource_updates.updates.is_empty()
|
||||
self.resource_updates.is_empty()
|
||||
}
|
||||
|
||||
// TODO: We only need this for a few RenderApi methods which we should remove.
|
||||
@ -378,7 +364,7 @@ impl TransactionMsg {
|
||||
TransactionMsg {
|
||||
scene_ops: Vec::new(),
|
||||
frame_ops: vec![msg],
|
||||
resource_updates: ResourceUpdates::new(),
|
||||
resource_updates: Vec::new(),
|
||||
generate_frame: false,
|
||||
use_scene_builder_thread: false,
|
||||
}
|
||||
@ -388,7 +374,7 @@ impl TransactionMsg {
|
||||
TransactionMsg {
|
||||
scene_ops: vec![msg],
|
||||
frame_ops: Vec::new(),
|
||||
resource_updates: ResourceUpdates::new(),
|
||||
resource_updates: Vec::new(),
|
||||
generate_frame: false,
|
||||
use_scene_builder_thread: false,
|
||||
}
|
||||
@ -598,11 +584,11 @@ pub enum DebugCommand {
|
||||
#[derive(Clone, Deserialize, Serialize)]
|
||||
pub enum ApiMsg {
|
||||
/// Add/remove/update images and fonts.
|
||||
UpdateResources(ResourceUpdates),
|
||||
UpdateResources(Vec<ResourceUpdate>),
|
||||
/// Gets the glyph dimensions
|
||||
GetGlyphDimensions(
|
||||
FontInstanceKey,
|
||||
Vec<GlyphKey>,
|
||||
Vec<GlyphIndex>,
|
||||
MsgSender<Vec<Option<GlyphDimensions>>>,
|
||||
),
|
||||
/// Gets the glyph indices from a string
|
||||
@ -811,10 +797,10 @@ impl RenderApi {
|
||||
pub fn get_glyph_dimensions(
|
||||
&self,
|
||||
font: FontInstanceKey,
|
||||
glyph_keys: Vec<GlyphKey>,
|
||||
glyph_indices: Vec<GlyphIndex>,
|
||||
) -> Vec<Option<GlyphDimensions>> {
|
||||
let (tx, rx) = channel::msg_channel().unwrap();
|
||||
let msg = ApiMsg::GetGlyphDimensions(font, glyph_keys, tx);
|
||||
let msg = ApiMsg::GetGlyphDimensions(font, glyph_indices, tx);
|
||||
self.api_sender.send(msg).unwrap();
|
||||
rx.recv().unwrap()
|
||||
}
|
||||
@ -835,8 +821,8 @@ impl RenderApi {
|
||||
}
|
||||
|
||||
/// Add/remove/update resources such as images and fonts.
|
||||
pub fn update_resources(&self, resources: ResourceUpdates) {
|
||||
if resources.updates.is_empty() {
|
||||
pub fn update_resources(&self, resources: Vec<ResourceUpdate>) {
|
||||
if resources.is_empty() {
|
||||
return;
|
||||
}
|
||||
self.api_sender
|
||||
|
@ -372,7 +372,7 @@ pub struct BorderSide {
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, Hash, Eq)]
|
||||
pub enum BorderStyle {
|
||||
None = 0,
|
||||
Solid = 1,
|
||||
|
@ -94,37 +94,7 @@ pub enum FontRenderMode {
|
||||
Subpixel,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug, Deserialize, Serialize, Ord, PartialOrd)]
|
||||
pub enum SubpixelDirection {
|
||||
None = 0,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
impl FontRenderMode {
|
||||
// Skia quantizes subpixel offsets into 1/4 increments.
|
||||
// Given the absolute position, return the quantized increment
|
||||
fn subpixel_quantize_offset(&self, pos: f32) -> SubpixelOffset {
|
||||
// Following the conventions of Gecko and Skia, we want
|
||||
// to quantize the subpixel position, such that abs(pos) gives:
|
||||
// [0.0, 0.125) -> Zero
|
||||
// [0.125, 0.375) -> Quarter
|
||||
// [0.375, 0.625) -> Half
|
||||
// [0.625, 0.875) -> ThreeQuarters,
|
||||
// [0.875, 1.0) -> Zero
|
||||
// The unit tests below check for this.
|
||||
let apos = ((pos - pos.floor()) * 8.0) as i32;
|
||||
|
||||
match apos {
|
||||
0 | 7 => SubpixelOffset::Zero,
|
||||
1...2 => SubpixelOffset::Quarter,
|
||||
3...4 => SubpixelOffset::Half,
|
||||
5...6 => SubpixelOffset::ThreeQuarters,
|
||||
_ => unreachable!("bug: unexpected quantized result"),
|
||||
}
|
||||
}
|
||||
|
||||
// Combine two font render modes such that the lesser amount of AA limits the AA of the result.
|
||||
pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode {
|
||||
match (self, other) {
|
||||
@ -134,36 +104,6 @@ impl FontRenderMode {
|
||||
}
|
||||
}
|
||||
|
||||
impl SubpixelDirection {
|
||||
// Limit the subpixel direction to what is supported by the render mode.
|
||||
pub fn limit_by(self, render_mode: FontRenderMode) -> SubpixelDirection {
|
||||
match render_mode {
|
||||
FontRenderMode::Mono => SubpixelDirection::None,
|
||||
FontRenderMode::Alpha | FontRenderMode::Subpixel => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Hash, Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
pub enum SubpixelOffset {
|
||||
Zero = 0,
|
||||
Quarter = 1,
|
||||
Half = 2,
|
||||
ThreeQuarters = 3,
|
||||
}
|
||||
|
||||
impl Into<f64> for SubpixelOffset {
|
||||
fn into(self) -> f64 {
|
||||
match self {
|
||||
SubpixelOffset::Zero => 0.0,
|
||||
SubpixelOffset::Quarter => 0.25,
|
||||
SubpixelOffset::Half => 0.5,
|
||||
SubpixelOffset::ThreeQuarters => 0.75,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialOrd, Deserialize, Serialize)]
|
||||
pub struct FontVariation {
|
||||
@ -222,6 +162,7 @@ bitflags! {
|
||||
const TRANSPOSE = 1 << 4;
|
||||
const FLIP_X = 1 << 5;
|
||||
const FLIP_Y = 1 << 6;
|
||||
const SUBPIXEL_POSITION = 1 << 7;
|
||||
|
||||
// Windows flags
|
||||
const FORCE_GDI = 1 << 16;
|
||||
@ -233,23 +174,25 @@ bitflags! {
|
||||
const FORCE_AUTOHINT = 1 << 16;
|
||||
const NO_AUTOHINT = 1 << 17;
|
||||
const VERTICAL_LAYOUT = 1 << 18;
|
||||
const LCD_VERTICAL = 1 << 19;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FontInstanceFlags {
|
||||
#[cfg(target_os = "windows")]
|
||||
fn default() -> FontInstanceFlags {
|
||||
FontInstanceFlags::empty()
|
||||
FontInstanceFlags::SUBPIXEL_POSITION
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn default() -> FontInstanceFlags {
|
||||
FontInstanceFlags::SUBPIXEL_POSITION |
|
||||
FontInstanceFlags::FONT_SMOOTHING
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||
fn default() -> FontInstanceFlags {
|
||||
FontInstanceFlags::empty()
|
||||
FontInstanceFlags::SUBPIXEL_POSITION
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,7 +201,6 @@ impl Default for FontInstanceFlags {
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
|
||||
pub struct FontInstanceOptions {
|
||||
pub render_mode: FontRenderMode,
|
||||
pub subpx_dir: SubpixelDirection,
|
||||
pub flags: FontInstanceFlags,
|
||||
/// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel,
|
||||
/// the text will be rendered with bg_color.r/g/b as an opaque estimated
|
||||
@ -270,7 +212,6 @@ impl Default for FontInstanceOptions {
|
||||
fn default() -> FontInstanceOptions {
|
||||
FontInstanceOptions {
|
||||
render_mode: FontRenderMode::Subpixel,
|
||||
subpx_dir: SubpixelDirection::Horizontal,
|
||||
flags: Default::default(),
|
||||
bg_color: ColorU::new(0, 0, 0, 0),
|
||||
}
|
||||
@ -358,32 +299,6 @@ impl FontInstanceKey {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash, PartialEq, Eq, Debug, Deserialize, Serialize, Ord, PartialOrd)]
|
||||
pub struct GlyphKey {
|
||||
pub index: u32,
|
||||
pub subpixel_offset: SubpixelOffset,
|
||||
}
|
||||
|
||||
impl GlyphKey {
|
||||
pub fn new(
|
||||
index: u32,
|
||||
point: LayoutPoint,
|
||||
render_mode: FontRenderMode,
|
||||
subpx_dir: SubpixelDirection,
|
||||
) -> GlyphKey {
|
||||
let pos = match subpx_dir {
|
||||
SubpixelDirection::None => 0.0,
|
||||
SubpixelDirection::Horizontal => point.x,
|
||||
SubpixelDirection::Vertical => point.y,
|
||||
};
|
||||
|
||||
GlyphKey {
|
||||
index,
|
||||
subpixel_offset: render_mode.subpixel_quantize_offset(pos),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type GlyphIndex = u32;
|
||||
|
||||
#[repr(C)]
|
||||
@ -393,52 +308,3 @@ pub struct GlyphInstance {
|
||||
pub point: LayoutPoint,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{FontRenderMode, SubpixelOffset};
|
||||
|
||||
#[test]
|
||||
fn test_subpx_quantize() {
|
||||
let rm = FontRenderMode::Subpixel;
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.0), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(-0.0), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.1), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.01), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.05), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.12), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.124), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.125), SubpixelOffset::Quarter);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.2), SubpixelOffset::Quarter);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.25), SubpixelOffset::Quarter);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.33), SubpixelOffset::Quarter);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.374), SubpixelOffset::Quarter);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.375), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.4), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.5), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.58), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.624), SubpixelOffset::Half);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.625), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.67), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.7), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.78), SubpixelOffset::ThreeQuarters);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.874), SubpixelOffset::ThreeQuarters);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.875), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.89), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.91), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.967), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(0.999), SubpixelOffset::Zero);
|
||||
|
||||
assert_eq!(rm.subpixel_quantize_offset(-1.0), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(1.0), SubpixelOffset::Zero);
|
||||
assert_eq!(rm.subpixel_quantize_offset(1.5), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(-1.625), SubpixelOffset::Half);
|
||||
assert_eq!(rm.subpixel_quantize_offset(-4.33), SubpixelOffset::ThreeQuarters);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ extern crate serde_bytes;
|
||||
|
||||
use font::{FontInstanceKey, FontKey, FontTemplate};
|
||||
use std::sync::Arc;
|
||||
use {DevicePoint, DeviceUintRect, DeviceUintSize, IdNamespace, TileOffset, TileSize};
|
||||
use {DevicePoint, DeviceUintPoint, DeviceUintRect, DeviceUintSize};
|
||||
use {IdNamespace, TileOffset, TileSize};
|
||||
use euclid::size2;
|
||||
|
||||
#[repr(C)]
|
||||
@ -106,6 +107,13 @@ impl ImageDescriptor {
|
||||
pub fn compute_total_size(&self) -> u32 {
|
||||
self.compute_stride() * self.size.height
|
||||
}
|
||||
|
||||
pub fn full_rect(&self) -> DeviceUintRect {
|
||||
DeviceUintRect::new(
|
||||
DeviceUintPoint::zero(),
|
||||
self.size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -92,6 +92,8 @@ pub type DevicePixelScale = TypedScale<f32, WorldPixel, DevicePixel>;
|
||||
/// Scaling ratio from layout to world. Used for cases where we know the layout
|
||||
/// is in world space, or specifically want to treat it this way.
|
||||
pub type LayoutToWorldScale = TypedScale<f32, LayoutPixel, WorldPixel>;
|
||||
/// A complete scaling ratio from layout space to device pixel space.
|
||||
pub type LayoutToDeviceScale = TypedScale<f32, LayoutPixel, DevicePixel>;
|
||||
|
||||
pub type LayoutTransform = TypedTransform3D<f32, LayoutPixel, LayoutPixel>;
|
||||
pub type LayoutToScrollTransform = TypedTransform3D<f32, LayoutPixel, ScrollLayerPixel>;
|
||||
|
@ -1 +1 @@
|
||||
bb354abbf84602d3d8357c63c4f0b1139ec4deb1
|
||||
63c71ca9bbe4dec0ebc9c9bc8ab65b06a6b40641
|
||||
|
@ -111,8 +111,8 @@ impl JsonFrameWriter {
|
||||
file.write_all(b"\n").unwrap();
|
||||
}
|
||||
|
||||
fn update_resources(&mut self, updates: &ResourceUpdates) {
|
||||
for update in &updates.updates {
|
||||
fn update_resources(&mut self, updates: &[ResourceUpdate]) {
|
||||
for update in updates {
|
||||
match *update {
|
||||
ResourceUpdate::AddImage(ref img) => {
|
||||
let stride = img.descriptor.stride.unwrap_or(
|
||||
|
@ -30,7 +30,9 @@ fn rect<T: Copy, U>(x: T, y: T, width: T, height: T) -> TypedRect<T, U> {
|
||||
}
|
||||
|
||||
impl<'a> RawtestHarness<'a> {
|
||||
pub fn new(wrench: &'a mut Wrench, window: &'a mut WindowWrapper, rx: &'a Receiver<NotifierEvent>) -> Self {
|
||||
pub fn new(wrench: &'a mut Wrench,
|
||||
window: &'a mut WindowWrapper,
|
||||
rx: &'a Receiver<NotifierEvent>) -> Self {
|
||||
RawtestHarness {
|
||||
wrench,
|
||||
rx,
|
||||
@ -45,6 +47,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
self.test_blob_update_epoch_test();
|
||||
self.test_tile_decomposition();
|
||||
self.test_very_large_blob();
|
||||
self.test_offscreen_blob();
|
||||
self.test_save_restore();
|
||||
self.test_capture();
|
||||
self.test_zero_height_window();
|
||||
@ -61,13 +64,13 @@ impl<'a> RawtestHarness<'a> {
|
||||
epoch: &mut Epoch,
|
||||
layout_size: LayoutSize,
|
||||
builder: DisplayListBuilder,
|
||||
resources: Option<ResourceUpdates>
|
||||
resources: &[ResourceUpdate]
|
||||
) {
|
||||
let mut txn = Transaction::new();
|
||||
let root_background_color = Some(ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
txn.use_scene_builder_thread();
|
||||
if let Some(resources) = resources {
|
||||
txn.update_resources(resources);
|
||||
if !resources.is_empty() {
|
||||
txn.resource_updates = resources.to_vec();
|
||||
}
|
||||
txn.set_display_list(
|
||||
*epoch,
|
||||
@ -82,14 +85,15 @@ impl<'a> RawtestHarness<'a> {
|
||||
self.wrench.api.send_transaction(self.wrench.document_id, txn);
|
||||
}
|
||||
|
||||
|
||||
fn test_tile_decomposition(&mut self) {
|
||||
println!("\ttile decomposition...");
|
||||
// This exposes a crash in tile decomposition
|
||||
let layout_size = LayoutSize::new(800., 800.);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
let blob_img = self.wrench.api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
@ -112,16 +116,16 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
self.rx.recv().unwrap();
|
||||
self.wrench.render();
|
||||
|
||||
// Leaving a tiled blob image in the resource cache
|
||||
// confuses the `test_capture`. TODO: remove this
|
||||
resources = ResourceUpdates::new();
|
||||
resources.delete_image(blob_img);
|
||||
self.wrench.api.update_resources(resources);
|
||||
txn = Transaction::new();
|
||||
txn.delete_image(blob_img);
|
||||
self.wrench.api.update_resources(txn.resource_updates);
|
||||
}
|
||||
|
||||
fn test_very_large_blob(&mut self) {
|
||||
@ -140,10 +144,10 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
// This exposes a crash in tile decomposition
|
||||
let layout_size = LayoutSize::new(800., 800.);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
let blob_img = self.wrench.api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(1510, 111256, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
@ -172,7 +176,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
let called = Arc::new(AtomicIsize::new(0));
|
||||
let called_inner = Arc::clone(&called);
|
||||
@ -188,23 +192,149 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
// make sure things are in the right spot
|
||||
assert!(
|
||||
pixels[(148 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4] == 255 &&
|
||||
pixels[(148 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 1] == 255 &&
|
||||
pixels[(148 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 2] == 255 &&
|
||||
pixels[(148 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 3] == 255
|
||||
pixels[(148 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4] == 255 &&
|
||||
pixels[(148 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 1] == 255 &&
|
||||
pixels[(148 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 2] == 255 &&
|
||||
pixels[(148 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 3] == 255
|
||||
);
|
||||
assert!(
|
||||
pixels[(132 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4] == 50 &&
|
||||
pixels[(132 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 1] == 50 &&
|
||||
pixels[(132 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 2] == 150 &&
|
||||
pixels[(132 + (window_rect.size.height as usize - 148) * window_rect.size.width as usize) * 4 + 3] == 255
|
||||
pixels[(132 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4] == 50 &&
|
||||
pixels[(132 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 1] == 50 &&
|
||||
pixels[(132 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 2] == 150 &&
|
||||
pixels[(132 +
|
||||
(window_rect.size.height as usize - 148) *
|
||||
window_rect.size.width as usize) * 4 + 3] == 255
|
||||
);
|
||||
|
||||
// Leaving a tiled blob image in the resource cache
|
||||
// confuses the `test_capture`. TODO: remove this
|
||||
resources = ResourceUpdates::new();
|
||||
resources.delete_image(blob_img);
|
||||
self.wrench.api.update_resources(resources);
|
||||
txn = Transaction::new();
|
||||
txn.delete_image(blob_img);
|
||||
self.wrench.api.update_resources(txn.resource_updates);
|
||||
}
|
||||
|
||||
fn test_offscreen_blob(&mut self) {
|
||||
println!("\toffscreen blob update.");
|
||||
|
||||
assert_eq!(self.wrench.device_pixel_ratio, 1.);
|
||||
|
||||
let window_size = self.window.get_inner_size();
|
||||
|
||||
let test_size = DeviceUintSize::new(800, 800);
|
||||
|
||||
let window_rect = DeviceUintRect::new(
|
||||
DeviceUintPoint::new(0, window_size.height - test_size.height),
|
||||
test_size,
|
||||
);
|
||||
|
||||
// This exposes a crash in tile decomposition
|
||||
let mut txn = Transaction::new();
|
||||
let layout_size = LayoutSize::new(800., 800.);
|
||||
|
||||
let blob_img = self.wrench.api.generate_image_key();
|
||||
txn.add_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(1510, 1510, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
None,
|
||||
);
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
|
||||
let info = LayoutPrimitiveInfo::new(rect(0., 0.0, 1510., 1510.));
|
||||
|
||||
let image_size = size(1510., 1510.);
|
||||
|
||||
// setup some malicious image size parameters
|
||||
builder.push_image(
|
||||
&info,
|
||||
image_size,
|
||||
image_size,
|
||||
ImageRendering::Auto,
|
||||
AlphaType::PremultipliedAlpha,
|
||||
blob_img,
|
||||
);
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
let original_pixels = self.render_and_get_pixels(window_rect);
|
||||
|
||||
let mut epoch = Epoch(1);
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
|
||||
let info = LayoutPrimitiveInfo::new(rect(-10000., 0.0, 1510., 1510.));
|
||||
|
||||
let image_size = size(1510., 1510.);
|
||||
|
||||
// setup some malicious image size parameters
|
||||
builder.push_image(
|
||||
&info,
|
||||
image_size,
|
||||
image_size,
|
||||
ImageRendering::Auto,
|
||||
AlphaType::PremultipliedAlpha,
|
||||
blob_img,
|
||||
);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &[]);
|
||||
|
||||
let _offscreen_pixels = self.render_and_get_pixels(window_rect);
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
txn.update_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(1510, 1510, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
Some(rect(10, 10, 100, 100)),
|
||||
);
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
|
||||
let info = LayoutPrimitiveInfo::new(rect(0., 0.0, 1510., 1510.));
|
||||
|
||||
let image_size = size(1510., 1510.);
|
||||
|
||||
// setup some malicious image size parameters
|
||||
builder.push_image(
|
||||
&info,
|
||||
image_size,
|
||||
image_size,
|
||||
ImageRendering::Auto,
|
||||
AlphaType::PremultipliedAlpha,
|
||||
blob_img,
|
||||
);
|
||||
|
||||
let mut epoch = Epoch(2);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
let pixels = self.render_and_get_pixels(window_rect);
|
||||
|
||||
assert!(pixels == original_pixels);
|
||||
|
||||
// Leaving a tiled blob image in the resource cache
|
||||
// confuses the `test_capture`. TODO: remove this
|
||||
txn = Transaction::new();
|
||||
txn.delete_image(blob_img);
|
||||
self.wrench.api.update_resources(txn.resource_updates);
|
||||
}
|
||||
|
||||
fn test_retained_blob_images_test(&mut self) {
|
||||
@ -219,12 +349,12 @@ impl<'a> RawtestHarness<'a> {
|
||||
test_size,
|
||||
);
|
||||
let layout_size = LayoutSize::new(400., 400.);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
{
|
||||
let api = &self.wrench.api;
|
||||
|
||||
blob_img = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
@ -247,7 +377,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
let called = Arc::new(AtomicIsize::new(0));
|
||||
let called_inner = Arc::clone(&called);
|
||||
@ -274,7 +404,9 @@ impl<'a> RawtestHarness<'a> {
|
||||
blob_img,
|
||||
);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, None);
|
||||
txn.resource_updates.clear();
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
let pixels_second = self.render_and_get_pixels(window_rect);
|
||||
|
||||
@ -300,19 +432,19 @@ impl<'a> RawtestHarness<'a> {
|
||||
test_size,
|
||||
);
|
||||
let layout_size = LayoutSize::new(400., 400.);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
let (blob_img, blob_img2) = {
|
||||
let api = &self.wrench.api;
|
||||
|
||||
blob_img = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
None,
|
||||
);
|
||||
blob_img2 = api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
blob_img2,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(80, 50, 150, 255))),
|
||||
@ -364,19 +496,19 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let _pixels_first = self.render_and_get_pixels(window_rect);
|
||||
|
||||
|
||||
// update and redraw both images
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.update_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
Some(rect(100, 100, 100, 100)),
|
||||
);
|
||||
resources.update_image(
|
||||
txn.update_image(
|
||||
blob_img2,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(59, 50, 150, 255))),
|
||||
@ -385,13 +517,13 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
push_images(&mut builder);
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let _pixels_second = self.render_and_get_pixels(window_rect);
|
||||
|
||||
|
||||
// only update the first image
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.update_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
|
||||
@ -400,7 +532,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
push_images(&mut builder);
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let _pixels_third = self.render_and_get_pixels(window_rect);
|
||||
|
||||
// the first image should be requested 3 times
|
||||
@ -420,11 +552,11 @@ impl<'a> RawtestHarness<'a> {
|
||||
test_size,
|
||||
);
|
||||
let layout_size = LayoutSize::new(400., 400.);
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
let blob_img = {
|
||||
let img = self.wrench.api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
@ -448,12 +580,12 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let pixels_first = self.render_and_get_pixels(window_rect);
|
||||
|
||||
// draw the blob image a second time after updating it with the same color
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.update_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))),
|
||||
@ -472,12 +604,12 @@ impl<'a> RawtestHarness<'a> {
|
||||
blob_img,
|
||||
);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let pixels_second = self.render_and_get_pixels(window_rect);
|
||||
|
||||
// draw the blob image a third time after updating it with a different color
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.update_image(
|
||||
let mut txn = Transaction::new();
|
||||
txn.update_image(
|
||||
blob_img,
|
||||
ImageDescriptor::new(500, 500, ImageFormat::BGRA8, false, false),
|
||||
ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))),
|
||||
@ -496,7 +628,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
blob_img,
|
||||
);
|
||||
|
||||
self.submit_dl(&mut epoch, layout_size, builder, Some(resources));
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
let pixels_third = self.render_and_get_pixels(window_rect);
|
||||
|
||||
assert!(pixels_first == pixels_second);
|
||||
@ -537,13 +669,13 @@ impl<'a> RawtestHarness<'a> {
|
||||
);
|
||||
builder.push_clip_id(clip);
|
||||
builder.push_rect(&PrimitiveInfo::new(rect(110., 110., 50., 50.)),
|
||||
ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
builder.push_shadow(&PrimitiveInfo::new(rect(100., 100., 100., 100.)),
|
||||
Shadow {
|
||||
offset: LayoutVector2D::new(1.0, 1.0),
|
||||
blur_radius: 1.0,
|
||||
color: ColorF::new(0.0, 0.0, 0.0, 1.0),
|
||||
});
|
||||
Shadow {
|
||||
offset: LayoutVector2D::new(1.0, 1.0),
|
||||
blur_radius: 1.0,
|
||||
color: ColorF::new(0.0, 0.0, 0.0, 1.0),
|
||||
});
|
||||
builder.push_line(&PrimitiveInfo::new(rect(110., 110., 50., 2.)),
|
||||
0.0, LineOrientation::Horizontal,
|
||||
&ColorF::new(0.0, 0.0, 0.0, 1.0), LineStyle::Solid);
|
||||
@ -567,7 +699,9 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
builder.pop_clip_id();
|
||||
|
||||
self.submit_dl(&mut Epoch(0), layout_size, builder, None);
|
||||
let txn = Transaction::new();
|
||||
|
||||
self.submit_dl(&mut Epoch(0), layout_size, builder, &txn.resource_updates);
|
||||
|
||||
self.render_and_get_pixels(window_rect)
|
||||
};
|
||||
@ -590,9 +724,9 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
// 1. render some scene
|
||||
|
||||
let mut resources = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
let image = self.wrench.api.generate_image_key();
|
||||
resources.add_image(
|
||||
txn.add_image(
|
||||
image,
|
||||
ImageDescriptor::new(1, 1, ImageFormat::BGRA8, true, false),
|
||||
ImageData::new(vec![0xFF, 0, 0, 0xFF]),
|
||||
@ -668,7 +802,8 @@ impl<'a> RawtestHarness<'a> {
|
||||
let doc_id = self.wrench.api.add_document(window_size, 1);
|
||||
|
||||
let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size);
|
||||
let info = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(), LayoutSize::new(100.0, 100.0)));
|
||||
let info = LayoutPrimitiveInfo::new(LayoutRect::new(LayoutPoint::zero(),
|
||||
LayoutSize::new(100.0, 100.0)));
|
||||
builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
|
||||
|
||||
let mut txn = Transaction::new();
|
||||
@ -709,7 +844,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
info.tag = Some((0, 2));
|
||||
builder.push_rect(&info, ColorF::new(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
let make_rounded_complex_clip = | rect: &LayoutRect, radius: f32 | -> ComplexClipRegion {
|
||||
let make_rounded_complex_clip = |rect: &LayoutRect, radius: f32| -> ComplexClipRegion {
|
||||
ComplexClipRegion::new(
|
||||
*rect,
|
||||
BorderRadius::uniform_size(LayoutSize::new(radius, radius)),
|
||||
@ -743,13 +878,14 @@ impl<'a> RawtestHarness<'a> {
|
||||
|
||||
|
||||
let mut epoch = Epoch(0);
|
||||
self.submit_dl(&mut epoch, layout_size, builder, None);
|
||||
let txn = Transaction::new();
|
||||
self.submit_dl(&mut epoch, layout_size, builder, &txn.resource_updates);
|
||||
|
||||
// We render to ensure that the hit tester is up to date with the current scene.
|
||||
self.rx.recv().unwrap();
|
||||
self.wrench.render();
|
||||
|
||||
let hit_test = | point: WorldPoint | -> HitTestResult {
|
||||
let hit_test = |point: WorldPoint| -> HitTestResult {
|
||||
self.wrench.api.hit_test(
|
||||
self.wrench.document_id,
|
||||
None,
|
||||
@ -758,7 +894,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
)
|
||||
};
|
||||
|
||||
let assert_hit_test = | point: WorldPoint, tags: Vec<ItemTag> | {
|
||||
let assert_hit_test = |point: WorldPoint, tags: Vec<ItemTag>| {
|
||||
let result = hit_test(point);
|
||||
assert_eq!(result.items.len(), tags.len());
|
||||
|
||||
@ -779,7 +915,7 @@ impl<'a> RawtestHarness<'a> {
|
||||
// The middle of the normal rectangle should be hit.
|
||||
assert_hit_test(WorldPoint::new(150., 50.), vec![(0, 2), (0, 1)]);
|
||||
|
||||
let test_rounded_rectangle = | point: WorldPoint, size: WorldSize, tag: ItemTag | {
|
||||
let test_rounded_rectangle = |point: WorldPoint, size: WorldSize, tag: ItemTag| {
|
||||
// The cut out corners of the rounded rectangle should not be hit.
|
||||
let top_left = point + WorldVector2D::new(5., 5.);
|
||||
let bottom_right = point + size.to_vector() - WorldVector2D::new(5., 5.);
|
||||
|
@ -87,8 +87,8 @@ impl RonFrameWriter {
|
||||
file.write_all(b"\n").unwrap();
|
||||
}
|
||||
|
||||
fn update_resources(&mut self, updates: &ResourceUpdates) {
|
||||
for update in &updates.updates {
|
||||
fn update_resources(&mut self, updates: &[ResourceUpdate]) {
|
||||
for update in updates {
|
||||
match *update {
|
||||
ResourceUpdate::AddImage(ref img) => {
|
||||
let bytes = match img.data {
|
||||
|
@ -280,7 +280,6 @@ impl Wrench {
|
||||
&mut self,
|
||||
font_key: FontKey,
|
||||
instance_key: FontInstanceKey,
|
||||
render_mode: Option<FontRenderMode>,
|
||||
text: &str,
|
||||
size: Au,
|
||||
origin: LayoutPoint,
|
||||
@ -294,20 +293,8 @@ impl Wrench {
|
||||
.filter_map(|idx| *idx)
|
||||
.collect();
|
||||
|
||||
let render_mode = render_mode.unwrap_or(<FontInstanceOptions as Default>::default().render_mode);
|
||||
let subpx_dir = SubpixelDirection::Horizontal.limit_by(render_mode);
|
||||
|
||||
// Retrieve the metrics for each glyph.
|
||||
let mut keys = Vec::new();
|
||||
for glyph_index in &indices {
|
||||
keys.push(GlyphKey::new(
|
||||
*glyph_index,
|
||||
LayoutPoint::zero(),
|
||||
render_mode,
|
||||
subpx_dir,
|
||||
));
|
||||
}
|
||||
let metrics = self.api.get_glyph_dimensions(instance_key, keys);
|
||||
let metrics = self.api.get_glyph_dimensions(instance_key, indices.clone());
|
||||
|
||||
let mut bounding_rect = LayoutRect::zero();
|
||||
let mut positions = Vec::new();
|
||||
@ -385,9 +372,9 @@ impl Wrench {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn font_key_from_native_handle(&mut self, descriptor: &NativeFontHandle) -> FontKey {
|
||||
let key = self.api.generate_font_key();
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.add_native_font(key, descriptor.clone());
|
||||
self.api.update_resources(resources);
|
||||
let mut txn = Transaction::new();
|
||||
txn.add_native_font(key, descriptor.clone());
|
||||
self.api.update_resources(txn.resource_updates);
|
||||
key
|
||||
}
|
||||
|
||||
@ -456,9 +443,9 @@ impl Wrench {
|
||||
|
||||
pub fn font_key_from_bytes(&mut self, bytes: Vec<u8>, index: u32) -> FontKey {
|
||||
let key = self.api.generate_font_key();
|
||||
let mut update = ResourceUpdates::new();
|
||||
update.add_raw_font(key, bytes, index);
|
||||
self.api.update_resources(update);
|
||||
let mut txn = Transaction::new();
|
||||
txn.add_raw_font(key, bytes, index);
|
||||
self.api.update_resources(txn.resource_updates);
|
||||
key
|
||||
}
|
||||
|
||||
@ -470,7 +457,7 @@ impl Wrench {
|
||||
bg_color: Option<ColorU>,
|
||||
) -> FontInstanceKey {
|
||||
let key = self.api.generate_font_instance_key();
|
||||
let mut update = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
let mut options: FontInstanceOptions = Default::default();
|
||||
options.flags |= flags;
|
||||
if let Some(render_mode) = render_mode {
|
||||
@ -479,16 +466,16 @@ impl Wrench {
|
||||
if let Some(bg_color) = bg_color {
|
||||
options.bg_color = bg_color;
|
||||
}
|
||||
update.add_font_instance(key, font_key, size, Some(options), None, Vec::new());
|
||||
self.api.update_resources(update);
|
||||
txn.add_font_instance(key, font_key, size, Some(options), None, Vec::new());
|
||||
self.api.update_resources(txn.resource_updates);
|
||||
key
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
|
||||
let mut update = ResourceUpdates::new();
|
||||
update.delete_font_instance(key);
|
||||
self.api.update_resources(update);
|
||||
let mut txn = Transaction::new();
|
||||
txn.delete_font_instance(key);
|
||||
self.api.update_resources(txn.resource_updates);
|
||||
}
|
||||
|
||||
pub fn update(&mut self, dim: DeviceUintSize) {
|
||||
|
@ -230,17 +230,17 @@ impl YamlFrameReader {
|
||||
}
|
||||
|
||||
pub fn deinit(mut self, wrench: &mut Wrench) {
|
||||
let mut updates = ResourceUpdates::new();
|
||||
let mut txn = Transaction::new();
|
||||
|
||||
for (_, font_instance) in self.font_instances.drain() {
|
||||
updates.delete_font_instance(font_instance);
|
||||
txn.delete_font_instance(font_instance);
|
||||
}
|
||||
|
||||
for (_, font) in self.fonts.drain() {
|
||||
updates.delete_font(font);
|
||||
txn.delete_font(font);
|
||||
}
|
||||
|
||||
wrench.api.update_resources(updates);
|
||||
wrench.api.update_resources(txn.resource_updates);
|
||||
}
|
||||
|
||||
pub fn yaml_path(&self) -> &PathBuf {
|
||||
@ -511,9 +511,9 @@ impl YamlFrameReader {
|
||||
};
|
||||
let tiling = tiling.map(|tile_size| tile_size as u16);
|
||||
let image_key = wrench.api.generate_image_key();
|
||||
let mut resources = ResourceUpdates::new();
|
||||
resources.add_image(image_key, descriptor, image_data, tiling);
|
||||
wrench.api.update_resources(resources);
|
||||
let mut txn = Transaction::new();
|
||||
txn.add_image(image_key, descriptor, image_data, tiling);
|
||||
wrench.api.update_resources(txn.resource_updates);
|
||||
let val = (
|
||||
image_key,
|
||||
LayoutSize::new(descriptor.size.width as f32, descriptor.size.height as f32),
|
||||
@ -1210,7 +1210,6 @@ impl YamlFrameReader {
|
||||
let (glyph_indices, glyph_positions, bounds) = wrench.layout_simple_ascii(
|
||||
font_key,
|
||||
font_instance_key,
|
||||
self.font_render_mode,
|
||||
text,
|
||||
size,
|
||||
origin,
|
||||
|
@ -503,8 +503,8 @@ impl YamlFrameWriter {
|
||||
scene.finish_display_list(self.pipeline_id.unwrap(), dl);
|
||||
}
|
||||
|
||||
fn update_resources(&mut self, updates: &ResourceUpdates) {
|
||||
for update in &updates.updates {
|
||||
fn update_resources(&mut self, updates: &[ResourceUpdate]) {
|
||||
for update in updates {
|
||||
match *update {
|
||||
ResourceUpdate::AddImage(ref img) => {
|
||||
if let Some(ref data) = self.images.get(&img.key) {
|
||||
@ -545,7 +545,8 @@ impl YamlFrameWriter {
|
||||
data.path = None;
|
||||
data.bytes = Some((**bytes).clone());
|
||||
} else {
|
||||
// Other existing image types only make sense within the gecko integration.
|
||||
// Other existing image types only make sense
|
||||
// within the gecko integration.
|
||||
println!(
|
||||
"Wrench only supports updating buffer images ({}).",
|
||||
"ignoring update command"
|
||||
|
Loading…
Reference in New Issue
Block a user