aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/script/dom/document.rs65
-rwxr-xr-xcomponents/style/binding_tools/regen.py18
-rw-r--r--components/style/gecko/conversions.rs15
-rw-r--r--components/style/gecko_bindings/bindings.rs57
-rw-r--r--components/style/stylesheets.rs35
-rw-r--r--ports/geckolib/glue.rs87
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json6
-rw-r--r--tests/wpt/mozilla/tests/mozilla/scroll_top_null_target.html21
8 files changed, 261 insertions, 43 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 0bf77ccf73d..b4273233c37 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -580,26 +580,18 @@ impl Document {
/// https://html.spec.whatwg.org/multipage/#the-indicated-part-of-the-document
pub fn find_fragment_node(&self, fragid: &str) -> Option<Root<Element>> {
// Step 1 is not handled here; the fragid is already obtained by the calling function
- // Step 2
- if fragid.is_empty() {
- self.GetDocumentElement()
- } else {
- // Step 3 & 4
- percent_decode(fragid.as_bytes()).decode_utf8().ok()
- // Step 5
- .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
- // Step 6
- .or_else(|| self.get_anchor_by_name(fragid))
- // Step 7
- .or_else(|| if fragid.eq_ignore_ascii_case("top") {
- self.GetDocumentElement()
- } else {
- // Step 8
- None
- })
- }
+ // Step 2: Simply use None to indicate the top of the document.
+ // Step 3 & 4
+ percent_decode(fragid.as_bytes()).decode_utf8().ok()
+ // Step 5
+ .and_then(|decoded_fragid| self.get_element_by_id(&Atom::from(decoded_fragid)))
+ // Step 6
+ .or_else(|| self.get_anchor_by_name(fragid))
+ // Step 7 & 8
}
+ /// Scroll to the target element, and when we do not find a target
+ /// and the fragment is empty or "top", scroll to the top.
/// https://html.spec.whatwg.org/multipage/#scroll-to-the-fragment-identifier
pub fn check_and_scroll_fragment(&self, fragment: &str) {
let target = self.find_fragment_node(fragment);
@@ -607,30 +599,27 @@ impl Document {
// Step 1
self.set_target_element(target.r());
- let point = if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
+ let point = target.r().map(|element| {
+ // FIXME(#8275, pcwalton): This is pretty bogus when multiple layers are involved.
+ // Really what needs to happen is that this needs to go through layout to ask which
+ // layer the element belongs to, and have it send the scroll message to the
+ // compositor.
+ let rect = element.upcast::<Node>().bounding_content_box();
+
+ // In order to align with element edges, we snap to unscaled pixel boundaries, since
+ // the paint thread currently does the same for drawing elements. This is important
+ // for pages that require pixel perfect scroll positioning for proper display
+ // (like Acid2). Since we don't have the device pixel ratio here, this might not be
+ // accurate, but should work as long as the ratio is a whole number. Once #8275 is
+ // fixed this should actually take into account the real device pixel ratio.
+ (rect.origin.x.to_nearest_px() as f32, rect.origin.y.to_nearest_px() as f32)
+ }).or_else(|| if fragment.is_empty() || fragment.eq_ignore_ascii_case("top") {
// FIXME(stshine): this should be the origin of the stacking context space,
// which may differ under the influence of writing mode.
Some((0.0, 0.0))
} else {
- target.r().map(|element| {
- // FIXME(#8275, pcwalton): This is pretty bogus when multiple layers
- // are involved. Really what needs to happen is that this needs to go
- // through layout to ask which layer the element belongs to, and have
- // it send the scroll message to the compositor.
- let rect = element.upcast::<Node>().bounding_content_box();
-
- // In order to align with element edges, we snap to unscaled pixel
- // boundaries, since the paint thread currently does the same for
- // drawing elements. This is important for pages that require pixel
- // perfect scroll positioning for proper display (like Acid2). Since
- // we don't have the device pixel ratio here, this might not be
- // accurate, but should work as long as the ratio is a whole number.
- // Once #8275 is fixed this should actually take into account the
- // real device pixel ratio.
- (rect.origin.x.to_nearest_px() as f32,
- rect.origin.y.to_nearest_px() as f32)
- })
- };
+ None
+ });
if let Some((x, y)) = point {
// Step 3
diff --git a/components/style/binding_tools/regen.py b/components/style/binding_tools/regen.py
index 4e0ef4b0e9b..b348cc0615b 100755
--- a/components/style/binding_tools/regen.py
+++ b/components/style/binding_tools/regen.py
@@ -328,9 +328,15 @@ COMPILATION_TARGETS = {
"nsStyleVisibility",
"nsStyleXUL",
],
+ "array_types": {
+ "uintptr_t": "usize",
+ },
"servo_nullable_arc_types": [
- "ServoComputedValues", "RawServoStyleSheet",
- "RawServoDeclarationBlock"
+ "ServoComputedValues",
+ "ServoCssRules",
+ "RawServoStyleSheet",
+ "RawServoDeclarationBlock",
+ "RawServoStyleRule",
],
"servo_owned_types": [
"RawServoStyleSet",
@@ -535,6 +541,14 @@ def build(objdir, target_name, debug, debugger, kind_name=None,
flags.append("--opaque-type")
flags.append(ty)
+ if "array_types" in current_target:
+ for cpp_type, rust_type in current_target["array_types"].items():
+ flags.append("--blacklist-type")
+ flags.append("nsTArrayBorrowed_{}".format(cpp_type))
+ flags.append("--raw-line")
+ flags.append("pub type nsTArrayBorrowed_{0}<'a> = &'a mut ::gecko_bindings::structs::nsTArray<{1}>;"
+ .format(cpp_type, rust_type))
+
if "blacklist_types" in current_target:
for ty in current_target["blacklist_types"]:
flags.append("--blacklist-type")
diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs
index 950003a2249..afca398c8b5 100644
--- a/components/style/gecko/conversions.rs
+++ b/components/style/gecko/conversions.rs
@@ -11,13 +11,14 @@
use app_units::Au;
use gecko::values::{convert_rgba_to_nscolor, StyleCoordHelpers};
use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue};
-use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, ServoComputedValues};
+use gecko_bindings::bindings::{RawServoStyleSheet, RawServoDeclarationBlock, RawServoStyleRule};
+use gecko_bindings::bindings::{ServoComputedValues, ServoCssRules};
use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage};
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasFFI};
use parking_lot::RwLock;
use properties::{ComputedValues, PropertyDeclarationBlock};
-use stylesheets::Stylesheet;
+use stylesheets::{CssRule, Stylesheet, StyleRule};
use values::computed::{CalcLengthOrPercentage, Gradient, Image, LengthOrPercentage, LengthOrPercentageOrAuto};
unsafe impl HasFFI for Stylesheet {
@@ -34,6 +35,16 @@ unsafe impl HasFFI for RwLock<PropertyDeclarationBlock> {
}
unsafe impl HasArcFFI for RwLock<PropertyDeclarationBlock> {}
+unsafe impl HasFFI for RwLock<Vec<CssRule>> {
+ type FFIType = ServoCssRules;
+}
+unsafe impl HasArcFFI for RwLock<Vec<CssRule>> {}
+
+unsafe impl HasFFI for RwLock<StyleRule> {
+ type FFIType = RawServoStyleRule;
+}
+unsafe impl HasArcFFI for RwLock<StyleRule> {}
+
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
let has_percentage = other.percentage.is_some();
diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs
index dcd961263c6..c00e7149da6 100644
--- a/components/style/gecko_bindings/bindings.rs
+++ b/components/style/gecko_bindings/bindings.rs
@@ -3,11 +3,17 @@
pub use nsstring::{nsACString, nsAString};
type nsACString_internal = nsACString;
type nsAString_internal = nsAString;
+pub type nsTArrayBorrowed_uintptr_t<'a> = &'a mut ::gecko_bindings::structs::nsTArray<usize>;
pub type ServoComputedValuesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoComputedValues>;
pub type ServoComputedValuesBorrowedOrNull<'a> = Option<&'a ServoComputedValues>;
pub type ServoComputedValuesBorrowed<'a> = &'a ServoComputedValues;
enum ServoComputedValuesVoid{ }
pub struct ServoComputedValues(ServoComputedValuesVoid);
+pub type ServoCssRulesStrong = ::gecko_bindings::sugar::ownership::Strong<ServoCssRules>;
+pub type ServoCssRulesBorrowedOrNull<'a> = Option<&'a ServoCssRules>;
+pub type ServoCssRulesBorrowed<'a> = &'a ServoCssRules;
+enum ServoCssRulesVoid{ }
+pub struct ServoCssRules(ServoCssRulesVoid);
pub type RawServoStyleSheetStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleSheet>;
pub type RawServoStyleSheetBorrowedOrNull<'a> = Option<&'a RawServoStyleSheet>;
pub type RawServoStyleSheetBorrowed<'a> = &'a RawServoStyleSheet;
@@ -18,6 +24,11 @@ pub type RawServoDeclarationBlockBorrowedOrNull<'a> = Option<&'a RawServoDeclara
pub type RawServoDeclarationBlockBorrowed<'a> = &'a RawServoDeclarationBlock;
enum RawServoDeclarationBlockVoid{ }
pub struct RawServoDeclarationBlock(RawServoDeclarationBlockVoid);
+pub type RawServoStyleRuleStrong = ::gecko_bindings::sugar::ownership::Strong<RawServoStyleRule>;
+pub type RawServoStyleRuleBorrowedOrNull<'a> = Option<&'a RawServoStyleRule>;
+pub type RawServoStyleRuleBorrowed<'a> = &'a RawServoStyleRule;
+enum RawServoStyleRuleVoid{ }
+pub struct RawServoStyleRule(RawServoStyleRuleVoid);
pub type RawGeckoNodeBorrowed<'a> = &'a RawGeckoNode;
pub type RawGeckoNodeBorrowedOrNull<'a> = Option<&'a RawGeckoNode>;
pub type RawGeckoElementBorrowed<'a> = &'a RawGeckoElement;
@@ -189,6 +200,12 @@ pub type RawGeckoNode = nsINode;
pub type RawGeckoElement = Element;
pub type RawGeckoDocument = nsIDocument;
extern "C" {
+ pub fn Servo_CssRules_AddRef(ptr: ServoCssRulesBorrowed);
+}
+extern "C" {
+ pub fn Servo_CssRules_Release(ptr: ServoCssRulesBorrowed);
+}
+extern "C" {
pub fn Servo_StyleSheet_AddRef(ptr: RawServoStyleSheetBorrowed);
}
extern "C" {
@@ -209,6 +226,12 @@ extern "C" {
RawServoDeclarationBlockBorrowed);
}
extern "C" {
+ pub fn Servo_StyleRule_AddRef(ptr: RawServoStyleRuleBorrowed);
+}
+extern "C" {
+ pub fn Servo_StyleRule_Release(ptr: RawServoStyleRuleBorrowed);
+}
+extern "C" {
pub fn Servo_StyleSet_Drop(ptr: RawServoStyleSetOwned);
}
extern "C" {
@@ -951,6 +974,10 @@ extern "C" {
-> bool;
}
extern "C" {
+ pub fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed)
+ -> ServoCssRulesStrong;
+}
+extern "C" {
pub fn Servo_StyleSet_Init() -> RawServoStyleSetOwned;
}
extern "C" {
@@ -975,6 +1002,36 @@ extern "C" {
RawServoStyleSheetBorrowed);
}
extern "C" {
+ pub fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
+ result: nsTArrayBorrowed_uintptr_t);
+}
+extern "C" {
+ pub fn Servo_CssRules_GetStyleRuleAt(rules: ServoCssRulesBorrowed,
+ index: u32)
+ -> RawServoStyleRuleStrong;
+}
+extern "C" {
+ pub fn Servo_StyleRule_Debug(rule: RawServoStyleRuleBorrowed,
+ result: *mut nsACString_internal);
+}
+extern "C" {
+ pub fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed)
+ -> RawServoDeclarationBlockStrong;
+}
+extern "C" {
+ pub fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+ declarations:
+ RawServoDeclarationBlockBorrowed);
+}
+extern "C" {
+ pub fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed,
+ result: *mut nsAString_internal);
+}
+extern "C" {
+ pub fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed,
+ result: *mut nsAString_internal);
+}
+extern "C" {
pub fn Servo_ParseProperty(property: *const nsACString_internal,
value: *const nsACString_internal,
base_url: *const nsACString_internal,
diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs
index 6e057e26f37..12ca0423cfa 100644
--- a/components/style/stylesheets.rs
+++ b/components/style/stylesheets.rs
@@ -136,6 +136,30 @@ pub enum CssRule {
Keyframes(Arc<RwLock<KeyframesRule>>),
}
+pub enum CssRuleType {
+ // https://drafts.csswg.org/cssom/#the-cssrule-interface
+ Style = 1,
+ Charset = 2,
+ Import = 3,
+ Media = 4,
+ FontFace = 5,
+ Page = 6,
+ // https://drafts.csswg.org/css-animations-1/#interface-cssrule-idl
+ Keyframes = 7,
+ Keyframe = 8,
+ // https://drafts.csswg.org/cssom/#the-cssrule-interface
+ Margin = 9,
+ Namespace = 10,
+ // https://drafts.csswg.org/css-counter-styles-3/#extentions-to-cssrule-interface
+ CounterStyle = 11,
+ // https://drafts.csswg.org/css-conditional-3/#extentions-to-cssrule-interface
+ Supports = 12,
+ // https://drafts.csswg.org/css-fonts-3/#om-fontfeaturevalues
+ FontFeatureValues = 14,
+ // https://drafts.csswg.org/css-device-adapt/#css-rule-interface
+ Viewport = 15,
+}
+
/// Error reporter which silently forgets errors
pub struct MemoryHoleReporter;
@@ -157,6 +181,17 @@ pub enum SingleRuleParseError {
}
impl CssRule {
+ pub fn rule_type(&self) -> CssRuleType {
+ match *self {
+ CssRule::Style(_) => CssRuleType::Style,
+ CssRule::Media(_) => CssRuleType::Media,
+ CssRule::FontFace(_) => CssRuleType::FontFace,
+ CssRule::Keyframes(_) => CssRuleType::Keyframes,
+ CssRule::Namespace(_) => CssRuleType::Namespace,
+ CssRule::Viewport(_) => CssRuleType::Viewport,
+ }
+ }
+
/// Call `f` with the slice of rules directly contained inside this rule.
///
/// Note that only some types of rules can contain rules. An empty slice is used for others.
diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs
index cf6d2a9a006..e65c8cbd5bd 100644
--- a/ports/geckolib/glue.rs
+++ b/ports/geckolib/glue.rs
@@ -4,6 +4,7 @@
use app_units::Au;
use cssparser::Parser;
+use cssparser::ToCss as ParserToCss;
use env_logger;
use euclid::Size2D;
use parking_lot::RwLock;
@@ -23,13 +24,16 @@ use style::gecko::wrapper::{GeckoElement, GeckoNode};
use style::gecko::wrapper::DUMMY_BASE_URL;
use style::gecko_bindings::bindings::{RawGeckoElementBorrowed, RawGeckoNodeBorrowed};
use style::gecko_bindings::bindings::{RawServoDeclarationBlockBorrowed, RawServoDeclarationBlockStrong};
+use style::gecko_bindings::bindings::{RawServoStyleRuleBorrowed, RawServoStyleRuleStrong};
use style::gecko_bindings::bindings::{RawServoStyleSetBorrowed, RawServoStyleSetOwned};
use style::gecko_bindings::bindings::{RawServoStyleSheetBorrowed, ServoComputedValuesBorrowed};
use style::gecko_bindings::bindings::{RawServoStyleSheetStrong, ServoComputedValuesStrong};
+use style::gecko_bindings::bindings::{ServoCssRulesBorrowed, ServoCssRulesStrong};
use style::gecko_bindings::bindings::{ThreadSafePrincipalHolder, ThreadSafeURIHolder};
use style::gecko_bindings::bindings::{nsACString, nsAString};
use style::gecko_bindings::bindings::Gecko_Utf8SliceToString;
use style::gecko_bindings::bindings::ServoComputedValuesBorrowedOrNull;
+use style::gecko_bindings::bindings::nsTArrayBorrowed_uintptr_t;
use style::gecko_bindings::structs::{SheetParsingMode, nsIAtom};
use style::gecko_bindings::structs::ServoElementSnapshot;
use style::gecko_bindings::structs::nsRestyleHint;
@@ -45,7 +49,7 @@ use style::properties::{apply_declarations, parse_one_declaration};
use style::selector_parser::PseudoElementCascadeType;
use style::sequential;
use style::string_cache::Atom;
-use style::stylesheets::{Origin, Stylesheet};
+use style::stylesheets::{CssRule, Origin, Stylesheet, StyleRule};
use style::thread_state;
use style::timer::Timer;
use style_traits::ToCss;
@@ -263,6 +267,11 @@ pub extern "C" fn Servo_StyleSheet_HasRules(raw_sheet: RawServoStyleSheetBorrowe
}
#[no_mangle]
+pub extern "C" fn Servo_StyleSheet_GetRules(sheet: RawServoStyleSheetBorrowed) -> ServoCssRulesStrong {
+ Stylesheet::as_arc(&sheet).rules.0.clone().into_strong()
+}
+
+#[no_mangle]
pub extern "C" fn Servo_StyleSheet_AddRef(sheet: RawServoStyleSheetBorrowed) -> () {
unsafe { Stylesheet::addref(sheet) };
}
@@ -273,6 +282,82 @@ pub extern "C" fn Servo_StyleSheet_Release(sheet: RawServoStyleSheetBorrowed) ->
}
#[no_mangle]
+pub extern "C" fn Servo_CssRules_ListTypes(rules: ServoCssRulesBorrowed,
+ result: nsTArrayBorrowed_uintptr_t) -> () {
+ let rules = RwLock::<Vec<CssRule>>::as_arc(&rules).read();
+ let iter = rules.iter().map(|rule| rule.rule_type() as usize);
+ let (size, upper) = iter.size_hint();
+ debug_assert_eq!(size, upper.unwrap());
+ unsafe { result.set_len(size as u32) };
+ result.iter_mut().zip(iter).fold((), |_, (r, v)| *r = v);
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_GetStyleRuleAt(rules: ServoCssRulesBorrowed, index: u32)
+ -> RawServoStyleRuleStrong {
+ let rules = RwLock::<Vec<CssRule>>::as_arc(&rules).read();
+ match rules[index as usize] {
+ CssRule::Style(ref rule) => rule.clone().into_strong(),
+ _ => {
+ unreachable!("GetStyleRuleAt should only be called on a style rule");
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_AddRef(rules: ServoCssRulesBorrowed) -> () {
+ unsafe { RwLock::<Vec<CssRule>>::addref(rules) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_CssRules_Release(rules: ServoCssRulesBorrowed) -> () {
+ unsafe { RwLock::<Vec<CssRule>>::release(rules) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_AddRef(rule: RawServoStyleRuleBorrowed) -> () {
+ unsafe { RwLock::<StyleRule>::addref(rule) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_Release(rule: RawServoStyleRuleBorrowed) -> () {
+ unsafe { RwLock::<StyleRule>::release(rule) };
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_Debug(rule: RawServoStyleRuleBorrowed, result: *mut nsACString) -> () {
+ let rule = RwLock::<StyleRule>::as_arc(&rule);
+ let result = unsafe { result.as_mut().unwrap() };
+ write!(result, "{:?}", *rule.read()).unwrap();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetStyle(rule: RawServoStyleRuleBorrowed) -> RawServoDeclarationBlockStrong {
+ let rule = RwLock::<StyleRule>::as_arc(&rule);
+ rule.read().block.clone().into_strong()
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_SetStyle(rule: RawServoStyleRuleBorrowed,
+ declarations: RawServoDeclarationBlockBorrowed) -> () {
+ let rule = RwLock::<StyleRule>::as_arc(&rule);
+ let declarations = RwLock::<PropertyDeclarationBlock>::as_arc(&declarations);
+ rule.write().block = declarations.clone();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetCssText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
+ let rule = RwLock::<StyleRule>::as_arc(&rule);
+ rule.read().to_css(unsafe { result.as_mut().unwrap() }).unwrap();
+}
+
+#[no_mangle]
+pub extern "C" fn Servo_StyleRule_GetSelectorText(rule: RawServoStyleRuleBorrowed, result: *mut nsAString) -> () {
+ let rule = RwLock::<StyleRule>::as_arc(&rule);
+ rule.read().selectors.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
+}
+
+#[no_mangle]
pub extern "C" fn Servo_ComputedValues_Get(node: RawGeckoNodeBorrowed)
-> ServoComputedValuesStrong {
let node = GeckoNode(node);
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index e146457901e..45dfabb2d13 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -14810,6 +14810,12 @@
"url": "/_mozilla/mozilla/scrollTo.html"
}
],
+ "mozilla/scroll_top_null_target.html": [
+ {
+ "path": "mozilla/scroll_top_null_target.html",
+ "url": "/_mozilla/mozilla/scroll_top_null_target.html"
+ }
+ ],
"mozilla/send-arraybuffer.htm": [
{
"path": "mozilla/send-arraybuffer.htm",
diff --git a/tests/wpt/mozilla/tests/mozilla/scroll_top_null_target.html b/tests/wpt/mozilla/tests/mozilla/scroll_top_null_target.html
new file mode 100644
index 00000000000..512bf34d506
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/scroll_top_null_target.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title></title>
+ <script src="/resources/testharness.js"></script>
+ <script src="/resources/testharnessreport.js"></script>
+ </head>
+ <body>
+ <a id="test"></a>
+ </body>
+ <script>
+ test(function() {
+ location.hash = "test";
+ assert_equals(document.querySelector(":target"), document.getElementById("test"),
+ "Target shoud be the same with the test anchor!");
+ location.hash = "";
+ assert_equals(document.querySelector(":target"), null, "Target should be null!");
+ });
+ </script>
+</html>