mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
parent
9c6d9f612e
commit
8bd2e91cdc
20 changed files with 296 additions and 346 deletions
471
Cargo.lock
generated
471
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -32,7 +32,7 @@ use std::fs::{File, create_dir_all};
|
|||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::time::{Duration, Instant};
|
||||
use std::time::Instant;
|
||||
use style_traits::{CSSPixel, DevicePixel, PinchZoomFactor};
|
||||
use style_traits::cursor::CursorKind;
|
||||
use style_traits::viewport::ViewportConstraints;
|
||||
|
@ -40,7 +40,7 @@ use time::{now, precise_time_ns, precise_time_s};
|
|||
use touch::{TouchHandler, TouchAction};
|
||||
use webrender;
|
||||
use webrender_api::{self, DeviceIntPoint, DevicePoint, HitTestFlags, HitTestResult};
|
||||
use webrender_api::{LayoutVector2D, ScrollEventPhase, ScrollLocation};
|
||||
use webrender_api::{LayoutVector2D, ScrollLocation};
|
||||
use windowing::{self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods};
|
||||
|
||||
|
||||
|
@ -200,8 +200,6 @@ struct ScrollZoomEvent {
|
|||
scroll_location: ScrollLocation,
|
||||
/// Apply changes to the frame at this location
|
||||
cursor: DeviceIntPoint,
|
||||
/// The scroll event phase.
|
||||
phase: ScrollEventPhase,
|
||||
/// The number of OS events that have been coalesced together into this one event.
|
||||
event_count: u32,
|
||||
}
|
||||
|
@ -793,7 +791,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
scroll_location: ScrollLocation::Delta(webrender_api::LayoutVector2D::from_untyped(
|
||||
&scroll_delta.to_untyped())),
|
||||
cursor: cursor,
|
||||
phase: ScrollEventPhase::Move(true),
|
||||
event_count: 1,
|
||||
});
|
||||
}
|
||||
|
@ -845,18 +842,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
fn on_scroll_window_event(&mut self,
|
||||
scroll_location: ScrollLocation,
|
||||
cursor: DeviceIntPoint) {
|
||||
let event_phase = match (self.scroll_in_progress, self.in_scroll_transaction) {
|
||||
(false, None) => ScrollEventPhase::Start,
|
||||
(false, Some(last_scroll)) if last_scroll.elapsed() > Duration::from_millis(80) =>
|
||||
ScrollEventPhase::Start,
|
||||
(_, _) => ScrollEventPhase::Move(self.scroll_in_progress),
|
||||
};
|
||||
self.in_scroll_transaction = Some(Instant::now());
|
||||
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
|
||||
magnification: 1.0,
|
||||
scroll_location: scroll_location,
|
||||
cursor: cursor,
|
||||
phase: event_phase,
|
||||
event_count: 1,
|
||||
});
|
||||
}
|
||||
|
@ -869,7 +859,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
magnification: 1.0,
|
||||
scroll_location: scroll_location,
|
||||
cursor: cursor,
|
||||
phase: ScrollEventPhase::Start,
|
||||
event_count: 1,
|
||||
});
|
||||
}
|
||||
|
@ -882,7 +871,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
magnification: 1.0,
|
||||
scroll_location: scroll_location,
|
||||
cursor: cursor,
|
||||
phase: ScrollEventPhase::End,
|
||||
event_count: 1,
|
||||
});
|
||||
}
|
||||
|
@ -905,44 +893,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
}
|
||||
};
|
||||
|
||||
if let Some(combined_event) = last_combined_event {
|
||||
if combined_event.phase != scroll_event.phase {
|
||||
let combined_delta = match combined_event.scroll_location {
|
||||
ScrollLocation::Delta(delta) => delta,
|
||||
ScrollLocation::Start | ScrollLocation::End => {
|
||||
// If this is an event which is scrolling to the start or end of the page,
|
||||
// disregard other pending events and exit the loop.
|
||||
last_combined_event = Some(scroll_event);
|
||||
break;
|
||||
}
|
||||
};
|
||||
// TODO: units don't match!
|
||||
let delta = combined_delta / self.scale.get();
|
||||
|
||||
let cursor =
|
||||
(combined_event.cursor.to_f32() / self.scale).to_untyped();
|
||||
let location = webrender_api::ScrollLocation::Delta(delta);
|
||||
let cursor = webrender_api::WorldPoint::from_untyped(&cursor);
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
txn.scroll(location, cursor, combined_event.phase);
|
||||
self.webrender_api.send_transaction(self.webrender_document, txn);
|
||||
last_combined_event = None
|
||||
}
|
||||
}
|
||||
|
||||
match (&mut last_combined_event, scroll_event.phase) {
|
||||
(last_combined_event @ &mut None, _) => {
|
||||
match &mut last_combined_event {
|
||||
last_combined_event @ &mut None => {
|
||||
*last_combined_event = Some(ScrollZoomEvent {
|
||||
magnification: scroll_event.magnification,
|
||||
scroll_location: ScrollLocation::Delta(webrender_api::LayoutVector2D::from_untyped(
|
||||
&this_delta.to_untyped())),
|
||||
cursor: this_cursor,
|
||||
phase: scroll_event.phase,
|
||||
event_count: 1,
|
||||
})
|
||||
}
|
||||
(&mut Some(ref mut last_combined_event),
|
||||
ScrollEventPhase::Move(false)) => {
|
||||
&mut Some(ref mut last_combined_event) => {
|
||||
// Mac OS X sometimes delivers scroll events out of vsync during a
|
||||
// fling. This causes events to get bunched up occasionally, causing
|
||||
// nasty-looking "pops". To mitigate this, during a fling we average
|
||||
|
@ -958,12 +919,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
new_event_count);
|
||||
}
|
||||
}
|
||||
(&mut Some(ref mut last_combined_event), _) => {
|
||||
if let ScrollLocation::Delta(delta) = last_combined_event.scroll_location {
|
||||
last_combined_event.scroll_location = ScrollLocation::Delta(delta + this_delta);
|
||||
last_combined_event.event_count += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -981,7 +936,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
let cursor = (combined_event.cursor.to_f32() / self.scale).to_untyped();
|
||||
let cursor = webrender_api::WorldPoint::from_untyped(&cursor);
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
txn.scroll(scroll_location, cursor, combined_event.phase);
|
||||
txn.scroll(scroll_location, cursor);
|
||||
self.webrender_api.send_transaction(self.webrender_document, txn);
|
||||
self.waiting_for_results_of_scroll = true
|
||||
}
|
||||
|
@ -1092,7 +1047,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
magnification: magnification,
|
||||
scroll_location: ScrollLocation::Delta(TypedVector2D::zero()), // TODO: Scroll to keep the center in view?
|
||||
cursor: TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
|
||||
phase: ScrollEventPhase::Move(true),
|
||||
event_count: 1,
|
||||
});
|
||||
}
|
||||
|
@ -1334,7 +1288,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.composition_request = CompositionRequest::NoCompositingNecessary;
|
||||
|
||||
self.process_animations();
|
||||
self.start_scrolling_bounce_if_necessary();
|
||||
self.waiting_for_results_of_scroll = false;
|
||||
|
||||
Ok(rv)
|
||||
|
@ -1355,19 +1308,6 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.root_pipeline.as_ref().map(|pipeline| pipeline.id)
|
||||
}
|
||||
|
||||
fn start_scrolling_bounce_if_necessary(&mut self) {
|
||||
if self.scroll_in_progress {
|
||||
return
|
||||
}
|
||||
|
||||
if self.webrender.layers_are_bouncing_back() {
|
||||
let mut txn = webrender_api::Transaction::new();
|
||||
txn.tick_scrolling_bounce_animations();
|
||||
self.webrender_api.send_transaction(self.webrender_document, txn);
|
||||
self.send_viewport_rects()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn receive_messages(&mut self) -> bool {
|
||||
// Check for new messages coming from the other threads in the system.
|
||||
let mut compositor_messages = vec![];
|
||||
|
|
|
@ -10,5 +10,5 @@ path = "lib.rs"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.12.12"
|
||||
synstructure = "0.7"
|
||||
syn = "0.13.1"
|
||||
synstructure = "0.8"
|
||||
|
|
|
@ -10,5 +10,5 @@ path = "lib.rs"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.12.12"
|
||||
quote = "0.4.2"
|
||||
syn = "0.13.1"
|
||||
quote = "0.5.1"
|
||||
|
|
|
@ -22,7 +22,7 @@ euclid = "0.17"
|
|||
fnv = "1.0"
|
||||
fontsan = {git = "https://github.com/servo/fontsan"}
|
||||
gfx_traits = {path = "../gfx_traits"}
|
||||
harfbuzz-sys = "0.1"
|
||||
harfbuzz-sys = "0.2"
|
||||
ipc-channel = "0.10"
|
||||
lazy_static = "1"
|
||||
libc = "0.2"
|
||||
|
@ -42,7 +42,7 @@ smallvec = "0.6"
|
|||
style = {path = "../style"}
|
||||
time = "0.1.12"
|
||||
unicode-bidi = {version = "0.3", features = ["with_serde"]}
|
||||
unicode-script = {version = "0.1", features = ["harfbuzz"]}
|
||||
unicode-script = {version = "0.2", features = ["harfbuzz"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
||||
xi-unicode = "0.1.0"
|
||||
|
||||
|
@ -53,7 +53,7 @@ core-graphics = "0.13"
|
|||
core-text = "9.0"
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
|
||||
freetype = "0.3"
|
||||
freetype = "0.4"
|
||||
servo_allocator = {path = "../allocator"}
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
|
|
|
@ -38,7 +38,7 @@ extern crate harfbuzz_sys as harfbuzz;
|
|||
extern crate ipc_channel;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate libc;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))] extern crate libc;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[cfg_attr(target_os = "windows", macro_use)]
|
||||
|
|
|
@ -14,6 +14,7 @@ use freetype::freetype::{FT_Int32, FT_Kerning_Mode, FT_STYLE_FLAG_ITALIC};
|
|||
use freetype::freetype::{FT_Load_Glyph, FT_Set_Char_Size};
|
||||
use freetype::freetype::{FT_SizeRec, FT_Size_Metrics, FT_UInt, FT_Vector};
|
||||
use freetype::freetype::FT_Sfnt_Tag;
|
||||
use freetype::succeeded;
|
||||
use freetype::tt_os2::TT_OS2;
|
||||
use platform::font_context::FontContextHandle;
|
||||
use platform::font_template::FontTemplateData;
|
||||
|
@ -78,7 +79,7 @@ impl Drop for FontHandle {
|
|||
fn drop(&mut self) {
|
||||
assert!(!self.face.is_null());
|
||||
unsafe {
|
||||
if !FT_Done_Face(self.face).succeeded() {
|
||||
if !succeeded(FT_Done_Face(self.face)) {
|
||||
panic!("FT_Done_Face failed");
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ impl FontHandleMethods for FontHandle {
|
|||
let result = FT_New_Memory_Face(lib, buffer.as_ptr(), buffer.len() as FT_Long,
|
||||
face_index, &mut face);
|
||||
|
||||
if !result.succeeded() || face.is_null() {
|
||||
if !succeeded(result) || face.is_null() {
|
||||
return Err(());
|
||||
}
|
||||
if let Some(s) = pt_size {
|
||||
|
@ -222,7 +223,7 @@ impl FontHandleMethods for FontHandle {
|
|||
let res = FT_Load_Glyph(self.face,
|
||||
glyph as FT_UInt,
|
||||
GLYPH_LOAD_FLAGS);
|
||||
if res.succeeded() {
|
||||
if succeeded(res) {
|
||||
let void_glyph = (*self.face).glyph;
|
||||
let slot: FT_GlyphSlot = mem::transmute(void_glyph);
|
||||
assert!(!slot.is_null());
|
||||
|
@ -296,12 +297,12 @@ impl FontHandleMethods for FontHandle {
|
|||
unsafe {
|
||||
// Get the length
|
||||
let mut len = 0;
|
||||
if !FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len).succeeded() {
|
||||
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, ptr::null_mut(), &mut len)) {
|
||||
return None
|
||||
}
|
||||
// Get the bytes
|
||||
let mut buf = vec![0u8; len as usize];
|
||||
if !FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len).succeeded() {
|
||||
if !succeeded(FT_Load_Sfnt_Table(self.face, tag, 0, buf.as_mut_ptr(), &mut len)) {
|
||||
return None
|
||||
}
|
||||
Some(FontTable { buffer: buf })
|
||||
|
@ -319,13 +320,13 @@ impl<'a> FontHandle {
|
|||
|
||||
unsafe {
|
||||
let result = FT_Set_Char_Size(face, char_size as FT_F26Dot6, 0, 0, 0);
|
||||
if result.succeeded() { Ok(()) } else { Err(()) }
|
||||
if succeeded(result) { Ok(()) } else { Err(()) }
|
||||
}
|
||||
}
|
||||
|
||||
fn has_table(&self, tag: FontTableTag) -> bool {
|
||||
unsafe {
|
||||
FT_Load_Sfnt_Table(self.face, tag as FT_ULong, 0, ptr::null_mut(), &mut 0).succeeded()
|
||||
succeeded(FT_Load_Sfnt_Table(self.face, tag as FT_ULong, 0, ptr::null_mut(), &mut 0))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ use freetype::freetype::FT_Library;
|
|||
use freetype::freetype::FT_Memory;
|
||||
use freetype::freetype::FT_MemoryRec_;
|
||||
use freetype::freetype::FT_New_Library;
|
||||
use freetype::succeeded;
|
||||
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
|
||||
use servo_allocator::libc_compat::{malloc, realloc, free};
|
||||
use servo_allocator::usable_size;
|
||||
|
@ -120,7 +121,7 @@ impl FontContextHandle {
|
|||
let mut ctx: FT_Library = ptr::null_mut();
|
||||
|
||||
let result = FT_New_Library(mem, &mut ctx);
|
||||
if !result.succeeded() { panic!("Unable to initialize FreeType library"); }
|
||||
if !succeeded(result) { panic!("Unable to initialize FreeType library"); }
|
||||
|
||||
FT_Add_Default_Modules(ctx);
|
||||
|
||||
|
|
|
@ -25,17 +25,17 @@ use harfbuzz::hb_face_destroy;
|
|||
use harfbuzz::hb_feature_t;
|
||||
use harfbuzz::hb_font_create;
|
||||
use harfbuzz::hb_font_funcs_create;
|
||||
use harfbuzz::hb_font_funcs_set_glyph_func;
|
||||
use harfbuzz::hb_font_funcs_set_glyph_h_advance_func;
|
||||
use harfbuzz::hb_font_funcs_set_glyph_h_kerning_func;
|
||||
use harfbuzz::hb_font_funcs_set_nominal_glyph_func;
|
||||
use harfbuzz::hb_font_set_funcs;
|
||||
use harfbuzz::hb_font_set_ppem;
|
||||
use harfbuzz::hb_font_set_scale;
|
||||
use harfbuzz::hb_glyph_info_t;
|
||||
use harfbuzz::hb_glyph_position_t;
|
||||
use libc::{c_char, c_int, c_uint, c_void};
|
||||
use platform::font::FontTable;
|
||||
use std::{char, cmp, ptr};
|
||||
use std::os::raw::{c_char, c_int, c_uint, c_void};
|
||||
use text::glyph::{ByteIndex, GlyphData, GlyphId, GlyphStore};
|
||||
use text::shaping::ShaperMethods;
|
||||
use text::util::{fixed_to_float, float_to_fixed, is_bidi_control};
|
||||
|
@ -418,7 +418,7 @@ unsafe impl Sync for FontFuncs {}
|
|||
lazy_static! {
|
||||
static ref HB_FONT_FUNCS: FontFuncs = unsafe {
|
||||
let hb_funcs = hb_font_funcs_create();
|
||||
hb_font_funcs_set_glyph_func(hb_funcs, Some(glyph_func), ptr::null_mut(), None);
|
||||
hb_font_funcs_set_nominal_glyph_func(hb_funcs, Some(glyph_func), ptr::null_mut(), None);
|
||||
hb_font_funcs_set_glyph_h_advance_func(
|
||||
hb_funcs, Some(glyph_h_advance_func), ptr::null_mut(), None);
|
||||
hb_font_funcs_set_glyph_h_kerning_func(
|
||||
|
@ -431,7 +431,6 @@ lazy_static! {
|
|||
extern fn glyph_func(_: *mut hb_font_t,
|
||||
font_data: *mut c_void,
|
||||
unicode: hb_codepoint_t,
|
||||
_: hb_codepoint_t,
|
||||
glyph: *mut hb_codepoint_t,
|
||||
_: *mut c_void)
|
||||
-> hb_bool_t {
|
||||
|
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.4.2"
|
||||
syn = "0.12.12"
|
||||
synstructure = "0.7"
|
||||
quote = "0.5.1"
|
||||
syn = "0.13.1"
|
||||
synstructure = "0.8"
|
||||
|
|
|
@ -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/. */
|
||||
|
||||
#[macro_use] extern crate quote;
|
||||
extern crate quote;
|
||||
#[macro_use] extern crate syn;
|
||||
#[macro_use] extern crate synstructure;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ smallvec = "0.6"
|
|||
style = {path = "../style", features = ["servo"]}
|
||||
style_traits = {path = "../style_traits"}
|
||||
unicode-bidi = {version = "0.3", features = ["with_serde"]}
|
||||
unicode-script = {version = "0.1", features = ["harfbuzz"]}
|
||||
unicode-script = {version = "0.2", features = ["harfbuzz"]}
|
||||
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}
|
||||
xi-unicode = "0.1.0"
|
||||
|
||||
|
|
|
@ -225,6 +225,7 @@ impl WebRenderDisplayItemConverter for DisplayItem {
|
|||
|
||||
builder.push_stacking_context(
|
||||
&webrender_api::LayoutPrimitiveInfo::new(stacking_context.bounds),
|
||||
None,
|
||||
stacking_context.scroll_policy,
|
||||
stacking_context.transform.map(Into::into),
|
||||
stacking_context.transform_style,
|
||||
|
|
|
@ -10,6 +10,6 @@ path = "lib.rs"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "0.4.2"
|
||||
syn = { version = "0.12.12", features = ["full"] }
|
||||
synstructure = "0.7"
|
||||
quote = "0.5.1"
|
||||
syn = { version = "0.13.1", features = ["full"] }
|
||||
synstructure = "0.8"
|
||||
|
|
|
@ -10,16 +10,10 @@
|
|||
|
||||
//! A crate for deriving the MallocSizeOf trait.
|
||||
|
||||
#[macro_use] extern crate quote;
|
||||
extern crate quote;
|
||||
#[macro_use] extern crate syn;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[macro_use] extern crate synstructure;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate synstructure;
|
||||
|
||||
|
||||
#[cfg(not(test))]
|
||||
decl_derive!([MallocSizeOf, attributes(ignore_malloc_size_of)] => malloc_size_of_derive);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ fnv = "1.0"
|
|||
hashglobe = { path = "../hashglobe" }
|
||||
html5ever = {version = "0.22", optional = true}
|
||||
itertools = "0.7.6"
|
||||
itoa = "0.3"
|
||||
itoa = "0.4"
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
malloc_size_of = { path = "../malloc_size_of" }
|
||||
|
@ -78,7 +78,7 @@ kernel32-sys = "0.2"
|
|||
[build-dependencies]
|
||||
lazy_static = "1"
|
||||
log = "0.4"
|
||||
bindgen = { version = "0.33.2", optional = true, default-features = false }
|
||||
bindgen = { version = "0.36", optional = true, default-features = false }
|
||||
regex = {version = "0.2", optional = true}
|
||||
walkdir = "2.1.4"
|
||||
toml = {version = "0.4.5", optional = true, default-features = false}
|
||||
|
|
|
@ -10,7 +10,7 @@ path = "lib.rs"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
darling = "0.3"
|
||||
quote = "0.4.2"
|
||||
syn = { version = "0.12.12", features = ["visit"] }
|
||||
synstructure = "0.7"
|
||||
darling = "0.4"
|
||||
quote = "0.5.1"
|
||||
syn = { version = "0.13.1", features = ["visit"] }
|
||||
synstructure = "0.8"
|
||||
|
|
|
@ -39,12 +39,14 @@ num = [
|
|||
# Ignored packages with duplicated versions
|
||||
packages = [
|
||||
"bitflags",
|
||||
"winapi",
|
||||
"syn",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
"itoa",
|
||||
"log",
|
||||
"rand"
|
||||
"num-traits",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
"winapi",
|
||||
]
|
||||
# Files that are ignored for all tidy and lint checks.
|
||||
files = [
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[mix-blend-mode-intermediate-element-overflow-hidden-and-border-radius.html]
|
||||
type: reftest
|
||||
expected:
|
||||
if os == "linux": FAIL
|
||||
bug: https://github.com/servo/webrender/issues/1776
|
|
@ -1,4 +0,0 @@
|
|||
[css3-box-shadow.html]
|
||||
type: reftest
|
||||
expected:
|
||||
if os == "linux": FAIL
|
Loading…
Add table
Add a link
Reference in a new issue