Move fragment navigation into Document object

Move the `check_and_scroll_fragment()` method into Document, make the
mothod set the fragment of url after navigation, and use the
`perform_a_scroll()` method to scroll rather than an individual
method. Also removes the broken `Window.fragment` fields.
This commit is contained in:
Pu Xingyu 2016-11-18 12:33:30 +08:00
parent eca8f1d0b4
commit 9863149043
5 changed files with 65 additions and 82 deletions

View file

@ -18,7 +18,7 @@ use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::Bindings::NodeFilterBinding::NodeFilter;
use dom::bindings::codegen::Bindings::PerformanceBinding::PerformanceMethods;
use dom::bindings::codegen::Bindings::TouchBinding::TouchMethods;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::Bindings::WindowBinding::{ScrollBehavior, WindowMethods};
use dom::bindings::codegen::UnionTypes::NodeOrString;
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::inheritance::{Castable, ElementTypeId, HTMLElementTypeId, NodeTypeId};
@ -600,6 +600,45 @@ impl Document {
}
}
/// 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);
// Step 1
self.set_target_element(target.r());
let point = if fragment.is_empty() || fragment.to_lowercase() == "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)
})
};
if let Some((x, y)) = point {
// Step 3
self.window.perform_a_scroll(x, y, ScrollBehavior::Instant,
target.r());
}
}
fn get_anchor_by_name(&self, name: &str) -> Option<Root<Element>> {
let check_anchor = |node: &HTMLAnchorElement| {
let elem = node.upcast::<Element>();

View file

@ -40,7 +40,7 @@ impl Location {
setter: fn(&mut ServoUrl, USVString)) {
let mut url = self.window.get_url();
setter(&mut url, value);
self.window.load_url(url, false, None);
self.window.load_url(url, false, false, None);
}
}
@ -51,7 +51,7 @@ impl LocationMethods for Location {
// _entry settings object_.
let base_url = self.window.get_url();
if let Ok(url) = base_url.join(&url.0) {
self.window.load_url(url, false, None);
self.window.load_url(url, false, false, None);
Ok(())
} else {
Err(Error::Syntax)
@ -60,7 +60,8 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-reload
fn Reload(&self) {
self.window.load_url(self.get_url(), true, None);
self.window.load_url(self.get_url(), true, true, None);
}
}
// https://html.spec.whatwg.org/multipage/#dom-location-hash
@ -109,7 +110,7 @@ impl LocationMethods for Location {
// https://html.spec.whatwg.org/multipage/#dom-location-href
fn SetHref(&self, value: USVString) {
if let Ok(url) = self.window.get_url().join(&value.0) {
self.window.load_url(url, false, None);
self.window.load_url(url, false, false, None);
}
}

View file

@ -103,6 +103,7 @@ use time;
use timers::{IsInterval, TimerCallback};
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
use tinyfiledialogs::{self, MessageBoxIcon};
use url::Position;
use util::geometry::{self, max_rect};
use util::opts;
use util::prefs::PREFS;
@ -205,9 +206,6 @@ pub struct Window {
#[ignore_heap_size_of = "channels are hard"]
bluetooth_thread: IpcSender<BluetoothRequest>,
/// Pending scroll to fragment event, if any
fragment_name: DOMRefCell<Option<String>>,
/// An enlarged rectangle around the page contents visible in the viewport, used
/// to prevent creating display list items for content that is far away from the viewport.
page_clip_rect: Cell<Rect<Au>>,
@ -1331,13 +1329,24 @@ impl Window {
}
/// Commence a new URL load which will either replace this window or scroll to a fragment.
pub fn load_url(&self, url: ServoUrl, replace: bool, referrer_policy: Option<ReferrerPolicy>) {
pub fn load_url(&self, url: ServoUrl, replace: bool, force_reload: bool,
referrer_policy: Option<ReferrerPolicy>) {
let doc = self.Document();
let referrer_policy = referrer_policy.or(doc.get_referrer_policy());
// https://html.spec.whatwg.org/multipage/#navigating-across-documents
if !force_reload && url.as_url().unwrap()[..Position::AfterQuery] == doc.url().as_url().unwrap()[..Position::AfterQuery] {
// Step 5
if let Some(fragment) = url.fragment() {
doc.check_and_scroll_fragment(fragment);
doc.set_url(url.clone());
return
}
}
self.main_thread_script_chan().send(
MainThreadScriptMsg::Navigate(self.upcast::<GlobalScope>().pipeline_id(),
LoadData::new(url, referrer_policy, Some(doc.url().clone())),
LoadData::new(url, referrer_policy, Some(doc.url())),
replace)).unwrap();
}
@ -1348,14 +1357,6 @@ impl Window {
ReflowReason::Timer);
}
pub fn set_fragment_name(&self, fragment: Option<String>) {
*self.fragment_name.borrow_mut() = fragment;
}
pub fn steal_fragment_name(&self) -> Option<String> {
self.fragment_name.borrow_mut().take()
}
pub fn set_window_size(&self, size: WindowSizeData) {
self.window_size.set(Some(size));
}