mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #13418 - stshine:location-replace, r=KiChjang
Make document url mutable and implement location.replace() <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #13413 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/13418) <!-- Reviewable:end -->
This commit is contained in:
commit
72e4c6dc21
26 changed files with 117 additions and 156 deletions
|
@ -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};
|
||||
|
@ -192,7 +192,7 @@ pub struct Document {
|
|||
last_modified: Option<String>,
|
||||
encoding: Cell<EncodingRef>,
|
||||
is_html_document: bool,
|
||||
url: ServoUrl,
|
||||
url: DOMRefCell<ServoUrl>,
|
||||
quirks_mode: Cell<QuirksMode>,
|
||||
/// Caches for the getElement methods
|
||||
id_map: DOMRefCell<HashMap<Atom, Vec<JS<Element>>>>,
|
||||
|
@ -398,8 +398,12 @@ impl Document {
|
|||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#concept-document-url
|
||||
pub fn url(&self) -> &ServoUrl {
|
||||
&self.url
|
||||
pub fn url(&self) -> ServoUrl {
|
||||
self.url.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn set_url(&self, url: ServoUrl) {
|
||||
*self.url.borrow_mut() = url;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#fallback-base-url
|
||||
|
@ -407,7 +411,7 @@ impl Document {
|
|||
// Step 1: iframe srcdoc (#4767).
|
||||
// Step 2: about:blank with a creator browsing context.
|
||||
// Step 3.
|
||||
self.url().clone()
|
||||
self.url()
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#document-base-url
|
||||
|
@ -587,7 +591,7 @@ impl Document {
|
|||
// Step 6
|
||||
.or_else(|| self.get_anchor_by_name(fragid))
|
||||
// Step 7
|
||||
.or_else(|| if fragid.to_lowercase() == "top" {
|
||||
.or_else(|| if fragid.eq_ignore_ascii_case("top") {
|
||||
self.GetDocumentElement()
|
||||
} else {
|
||||
// Step 8
|
||||
|
@ -596,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.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)
|
||||
})
|
||||
};
|
||||
|
||||
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>();
|
||||
|
@ -1709,7 +1752,7 @@ impl Document {
|
|||
|
||||
/// https://html.spec.whatwg.org/multipage/#cookie-averse-document-object
|
||||
pub fn is_cookie_averse(&self) -> bool {
|
||||
self.browsing_context.is_none() || !url_has_network_scheme(&self.url)
|
||||
self.browsing_context.is_none() || !url_has_network_scheme(&self.url())
|
||||
}
|
||||
|
||||
pub fn nodes_from_point(&self, client_point: &Point2D<f32>) -> Vec<UntrustedNodeAddress> {
|
||||
|
@ -1814,7 +1857,7 @@ impl Document {
|
|||
}),
|
||||
},
|
||||
last_modified: last_modified,
|
||||
url: url,
|
||||
url: DOMRefCell::new(url),
|
||||
// https://dom.spec.whatwg.org/#concept-document-quirks
|
||||
quirks_mode: Cell::new(NoQuirks),
|
||||
// https://dom.spec.whatwg.org/#concept-document-encoding
|
||||
|
@ -2787,7 +2830,7 @@ impl DocumentMethods for Document {
|
|||
let _ = self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(GetCookiesForUrl((*url).clone(), tx, NonHTTP));
|
||||
.send(GetCookiesForUrl(url, tx, NonHTTP));
|
||||
let cookies = rx.recv().unwrap();
|
||||
Ok(cookies.map_or(DOMString::new(), DOMString::from))
|
||||
}
|
||||
|
@ -2806,7 +2849,7 @@ impl DocumentMethods for Document {
|
|||
let _ = self.window
|
||||
.upcast::<GlobalScope>()
|
||||
.resource_threads()
|
||||
.send(SetCookiesForUrl((*url).clone(), String::from(cookie), NonHTTP));
|
||||
.send(SetCookiesForUrl(url, String::from(cookie), NonHTTP));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -615,5 +615,5 @@ fn follow_hyperlink(subject: &Element, hyperlink_suffix: Option<String>, referre
|
|||
debug!("following hyperlink to {}", url);
|
||||
|
||||
let window = document.window();
|
||||
window.load_url(url, false, referrer_policy);
|
||||
window.load_url(url, false, false, referrer_policy);
|
||||
}
|
||||
|
|
|
@ -341,7 +341,7 @@ impl HTMLFormElement {
|
|||
let _target = submitter.target();
|
||||
// TODO: Handle browsing contexts, partially loaded documents (step 16-17)
|
||||
|
||||
let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url().clone()));
|
||||
let mut load_data = LoadData::new(action_components, doc.get_referrer_policy(), Some(doc.url()));
|
||||
|
||||
// Step 18
|
||||
match (&*scheme, method) {
|
||||
|
|
|
@ -157,7 +157,7 @@ impl HTMLIFrameElement {
|
|||
|
||||
let document = document_from_node(self);
|
||||
self.navigate_or_reload_child_browsing_context(
|
||||
Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url().clone()))), false);
|
||||
Some(LoadData::new(url, document.get_referrer_policy(), Some(document.url()))), false);
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
|
|
|
@ -280,9 +280,9 @@ impl HTMLLinkElement {
|
|||
destination: Destination::Style,
|
||||
credentials_mode: CredentialsMode::Include,
|
||||
use_url_credentials: true,
|
||||
origin: document.url().clone(),
|
||||
origin: document.url(),
|
||||
pipeline_id: Some(self.global().pipeline_id()),
|
||||
referrer_url: Some(document.url().clone()),
|
||||
referrer_url: Some(document.url()),
|
||||
referrer_policy: referrer_policy,
|
||||
.. RequestInit::default()
|
||||
};
|
||||
|
|
|
@ -548,9 +548,9 @@ impl HTMLMediaElement {
|
|||
destination: Destination::Media,
|
||||
credentials_mode: CredentialsMode::Include,
|
||||
use_url_credentials: true,
|
||||
origin: document.url().clone(),
|
||||
origin: document.url(),
|
||||
pipeline_id: Some(self.global().pipeline_id()),
|
||||
referrer_url: Some(document.url().clone()),
|
||||
referrer_url: Some(document.url()),
|
||||
referrer_policy: document.get_referrer_policy(),
|
||||
.. RequestInit::default()
|
||||
};
|
||||
|
|
|
@ -241,9 +241,9 @@ fn fetch_a_classic_script(script: &HTMLScriptElement,
|
|||
Some(CorsSettings::Anonymous) => CredentialsMode::CredentialsSameOrigin,
|
||||
_ => CredentialsMode::Include,
|
||||
},
|
||||
origin: doc.url().clone(),
|
||||
origin: doc.url(),
|
||||
pipeline_id: Some(script.global().pipeline_id()),
|
||||
referrer_url: Some(doc.url().clone()),
|
||||
referrer_url: Some(doc.url()),
|
||||
referrer_policy: doc.get_referrer_policy(),
|
||||
.. RequestInit::default()
|
||||
};
|
||||
|
|
|
@ -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,20 @@ 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-replace
|
||||
fn Replace(&self, url: USVString) -> ErrorResult {
|
||||
// TODO: per spec, we should use the _API base URL_ specified by the
|
||||
// _entry settings object_.
|
||||
let base_url = self.window.get_url();
|
||||
if let Ok(url) = base_url.join(&url.0) {
|
||||
self.window.load_url(url, true, false, None);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::Syntax)
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-location-hash
|
||||
|
@ -109,7 +122,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ macro_rules! make_string_or_document_url_getter(
|
|||
|
||||
if val.is_empty() {
|
||||
let doc = document_from_node(self);
|
||||
DOMString::from(doc.url().clone().into_string())
|
||||
DOMString::from(doc.url().into_string())
|
||||
} else {
|
||||
val
|
||||
}
|
||||
|
|
|
@ -1751,7 +1751,7 @@ impl Node {
|
|||
let window = document.window();
|
||||
let loader = DocumentLoader::new(&*document.loader());
|
||||
let document = Document::new(window, None,
|
||||
Some((*document.url()).clone()),
|
||||
Some(document.url()),
|
||||
is_html_doc, None,
|
||||
None, DocumentSource::NotFromParser, loader,
|
||||
None, None);
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
[Throws]
|
||||
void assign(USVString url);
|
||||
//void replace(USVString url);
|
||||
[Throws]
|
||||
void replace(USVString url);
|
||||
void reload();
|
||||
|
||||
//[SameObject] readonly attribute USVString[] ancestorOrigins;
|
||||
|
|
|
@ -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,25 @@ 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 +1358,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));
|
||||
}
|
||||
|
@ -1365,7 +1367,7 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn get_url(&self) -> ServoUrl {
|
||||
(*self.Document().url()).clone()
|
||||
self.Document().url()
|
||||
}
|
||||
|
||||
pub fn layout_chan(&self) -> &Sender<Msg> {
|
||||
|
@ -1588,7 +1590,6 @@ impl Window {
|
|||
js_runtime: DOMRefCell::new(Some(runtime.clone())),
|
||||
bluetooth_thread: bluetooth_thread,
|
||||
page_clip_rect: Cell::new(max_rect()),
|
||||
fragment_name: DOMRefCell::new(None),
|
||||
resize_event: Cell::new(None),
|
||||
layout_chan: layout_chan,
|
||||
layout_rpc: layout_rpc,
|
||||
|
|
|
@ -159,7 +159,7 @@ impl XMLHttpRequest {
|
|||
//TODO - update this when referrer policy implemented for workers
|
||||
let (referrer_url, referrer_policy) = if let Some(window) = global.downcast::<Window>() {
|
||||
let document = window.Document();
|
||||
(Some(document.url().clone()), document.get_referrer_policy())
|
||||
(Some(document.url()), document.get_referrer_policy())
|
||||
} else {
|
||||
(None, None)
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue