diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index e6484bae8d1..7a1914bbbb9 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -454,6 +454,14 @@ impl IOCompositor { self.composite_if_necessary(CompositingReason::Headless); } + (Msg::NewFavicon(url), ShutdownState::NotShuttingDown) => { + self.window.set_favicon(url); + } + + (Msg::HeadParsed, ShutdownState::NotShuttingDown) => { + self.window.head_parsed(); + } + // When we are shutting_down, we need to avoid performing operations // such as Paint that may crash because we have begun tearing down // the rest of our resources. diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs index be134d751bc..9e7b172cc80 100644 --- a/components/compositing/compositor_task.rs +++ b/components/compositing/compositor_task.rs @@ -180,6 +180,10 @@ pub enum Msg { ViewportConstrained(PipelineId, ViewportConstraints), /// A reply to the compositor asking if the output image is stable. IsReadyToSaveImageReply(bool), + /// A favicon was detected + NewFavicon(Url), + /// tag finished parsing + HeadParsed, } impl Debug for Msg { @@ -206,6 +210,8 @@ impl Debug for Msg { Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"), Msg::ViewportConstrained(..) => write!(f, "ViewportConstrained"), Msg::IsReadyToSaveImageReply(..) => write!(f, "IsReadyToSaveImageReply"), + Msg::NewFavicon(..) => write!(f, "NewFavicon"), + Msg::HeadParsed => write!(f, "HeadParsed"), } } } diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 51aad901cf6..cf361b9a059 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -468,6 +468,14 @@ impl Constellation { debug!("constellation got remove iframe message"); self.handle_remove_iframe_msg(containing_pipeline_id, subpage_id); } + ConstellationMsg::NewFavicon(url) => { + debug!("constellation got new favicon message"); + self.compositor_proxy.send(CompositorMsg::NewFavicon(url)); + } + ConstellationMsg::HeadParsed => { + debug!("constellation got head parsed message"); + self.compositor_proxy.send(CompositorMsg::HeadParsed); + } } true } diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs index c58532e81ed..ed3afa6a4b0 100644 --- a/components/compositing/headless.rs +++ b/components/compositing/headless.rs @@ -109,6 +109,8 @@ impl CompositorEventListener for NullCompositor { Msg::CreatePng(..) | Msg::PaintTaskExited(..) | Msg::IsReadyToSaveImageReply(..) => {} + Msg::NewFavicon(..) => {} + Msg::HeadParsed => {} } true } diff --git a/components/compositing/windowing.rs b/components/compositing/windowing.rs index 7ba7fffe449..17ce9f43434 100644 --- a/components/compositing/windowing.rs +++ b/components/compositing/windowing.rs @@ -110,6 +110,8 @@ pub trait WindowMethods { fn load_end(&self, back: bool, forward: bool); /// Called when the browser encounters an error while loading a URL fn load_error(&self, code: NetError, url: String); + /// Called when the tag has finished parsing + fn head_parsed(&self); /// Returns the hidpi factor of the monitor. fn hidpi_factor(&self) -> ScaleFactor; @@ -138,4 +140,7 @@ pub trait WindowMethods { /// Does this window support a clipboard fn supports_clipboard(&self) -> bool; + + /// Add a favicon + fn set_favicon(&self, url: Url); } diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 8a8135b0071..c8d5bf0ceb2 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -248,6 +248,10 @@ pub enum Msg { IsReadyToSaveImage(HashMap), /// Notification that this iframe should be removed. RemoveIFrame(PipelineId, SubpageId), + /// Favicon detected + NewFavicon(Url), + /// tag finished parsing + HeadParsed, } #[derive(Clone, Eq, PartialEq)] diff --git a/components/script/dom/htmlbodyelement.rs b/components/script/dom/htmlbodyelement.rs index 97cd615f910..fc2b0cf1d57 100644 --- a/components/script/dom/htmlbodyelement.rs +++ b/components/script/dom/htmlbodyelement.rs @@ -17,6 +17,8 @@ use dom::htmlelement::{HTMLElement, HTMLElementTypeId}; use dom::node::{Node, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom::window::WindowHelpers; +use msg::constellation_msg::ConstellationChan; +use msg::constellation_msg::Msg as ConstellationMsg; use cssparser::RGBA; use util::str::{self, DOMString}; @@ -107,6 +109,9 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLBodyElement> { let window = window_from_node(*self).root(); let document = window.r().Document().root(); document.r().set_reflow_timeout(time::precise_time_ns() + INITIAL_REFLOW_DELAY); + let ConstellationChan(ref chan) = window.r().constellation_chan(); + let event = ConstellationMsg::HeadParsed; + chan.send(event).unwrap(); } fn after_set_attr(&self, attr: JSRef) { diff --git a/components/script/dom/htmllinkelement.rs b/components/script/dom/htmllinkelement.rs index c0d38221e2e..a707942544f 100644 --- a/components/script/dom/htmllinkelement.rs +++ b/components/script/dom/htmllinkelement.rs @@ -25,6 +25,8 @@ use dom::node::{Node, NodeHelpers, NodeTypeId, window_from_node}; use dom::virtualmethods::VirtualMethods; use dom::window::WindowHelpers; use layout_interface::{LayoutChan, Msg}; +use msg::constellation_msg::ConstellationChan; +use msg::constellation_msg::Msg as ConstellationMsg; use script_traits::StylesheetLoadResponder; use util::str::{DOMString, HTML_SPACE_CHARACTERS}; use style::media_queries::parse_media_query_list; @@ -85,6 +87,19 @@ fn is_stylesheet(value: &Option) -> bool { } } +/// Favicon spec usage in accordance with CEF implementation: +/// only url of icon is required/used +/// https://html.spec.whatwg.org/multipage/#rel-icon +fn is_favicon(value: &Option) -> bool { + match *value { + Some(ref value) => { + value.split(HTML_SPACE_CHARACTERS) + .any(|s| s.eq_ignore_ascii_case("icon")) + }, + None => false, + } +} + impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { fn super_type<'b>(&'b self) -> Option<&'b VirtualMethods> { let htmlelement: &JSRef = HTMLElementCast::from_borrowed_ref(self); @@ -105,7 +120,14 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { let rel = get_attr(element, &atom!("rel")); match (rel, attr.local_name()) { - (ref rel, &atom!("href")) | (ref rel, &atom!("media")) => { + (ref rel, &atom!("href")) => { + if is_stylesheet(rel) { + self.handle_stylesheet_url(&attr.value()); + } else if is_favicon(rel) { + self.handle_favicon_url(&attr.value()); + } + } + (ref rel, &atom!("media")) => { if is_stylesheet(rel) { self.handle_stylesheet_url(&attr.value()); } @@ -136,6 +158,9 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { (ref rel, Some(ref href)) if is_stylesheet(rel) => { self.handle_stylesheet_url(href); } + (ref rel, Some(ref href)) if is_favicon(rel) => { + self.handle_favicon_url(href); + } _ => {} } } @@ -144,6 +169,7 @@ impl<'a> VirtualMethods for JSRef<'a, HTMLLinkElement> { trait PrivateHTMLLinkElementHelpers { fn handle_stylesheet_url(self, href: &str); + fn handle_favicon_url(self, href: &str); } impl<'a> PrivateHTMLLinkElementHelpers for JSRef<'a, HTMLLinkElement> { @@ -174,6 +200,19 @@ impl<'a> PrivateHTMLLinkElementHelpers for JSRef<'a, HTMLLinkElement> { Err(e) => debug!("Parsing url {} failed: {}", href, e) } } + + fn handle_favicon_url(self, href: &str) { + let window = window_from_node(self).root(); + let window = window.r(); + match UrlParser::new().base_url(&window.get_url()).parse(href) { + Ok(url) => { + let ConstellationChan(ref chan) = window.constellation_chan(); + let event = ConstellationMsg::NewFavicon(url.clone()); + chan.send(event).unwrap(); + } + Err(e) => debug!("Parsing url {} failed: {}", href, e) + } + } } impl<'a> HTMLLinkElementMethods for JSRef<'a, HTMLLinkElement> { diff --git a/ports/cef/browser.rs b/ports/cef/browser.rs index 4dded7202c0..dd8f99f1295 100644 --- a/ports/cef/browser.rs +++ b/ports/cef/browser.rs @@ -111,6 +111,8 @@ pub struct ServoCefBrowser { pub forward: Cell, /// whether the browser is loading pub loading: Cell, + /// a vec of favicon urls for the current page + pub favicons: RefCell>, /// the display system window handle: only to be used with host.get_window_handle() window_handle: cef_window_handle_t, @@ -154,6 +156,7 @@ impl ServoCefBrowser { back: Cell::new(false), forward: Cell::new(false), loading: Cell::new(false), + favicons: RefCell::new(vec!()), window_handle: window_handle, } } diff --git a/ports/cef/interfaces/cef_browser.rs b/ports/cef/interfaces/cef_browser.rs index 57db64c60a2..360f2ff6b7f 100644 --- a/ports/cef/interfaces/cef_browser.rs +++ b/ports/cef/interfaces/cef_browser.rs @@ -174,7 +174,7 @@ pub struct _cef_browser_t { // Returns the names of all existing frames. // pub get_frame_names: Option ()>, + names: &types::cef_string_list_t) -> ()>, // // Send a message to the specified |target_process|. Returns true (1) if the @@ -567,7 +567,7 @@ impl CefBrowser { // // Returns the names of all existing frames. // - pub fn get_frame_names(&self, names: Vec) -> () { + pub fn get_frame_names(&self, names: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -647,7 +647,7 @@ pub struct _cef_run_file_dialog_callback_t { pub on_file_dialog_dismissed: Option ()>, + file_paths: &types::cef_string_list_t) -> ()>, // // The reference count. This will only be present for Rust instances! @@ -742,7 +742,7 @@ impl CefRunFileDialogCallback { // dialog mode. If the selection was cancelled |file_paths| will be NULL. // pub fn on_file_dialog_dismissed(&self, selected_accept_filter: libc::c_int, - file_paths: Vec) -> () { + file_paths: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -1047,7 +1047,7 @@ pub struct _cef_browser_host_t { pub run_file_dialog: Option ()>, @@ -1606,7 +1606,7 @@ impl CefBrowserHost { // will be initiated asynchronously on the UI thread. // pub fn run_file_dialog(&self, mode: types::cef_file_dialog_mode_t, - title: &[u16], default_file_path: &[u16], accept_filters: Vec, + title: &[u16], default_file_path: &[u16], accept_filters: &Vec, selected_accept_filter: libc::c_int, callback: interfaces::CefRunFileDialogCallback) -> () { if self.c_object.is_null() || diff --git a/ports/cef/interfaces/cef_browser_process_handler.rs b/ports/cef/interfaces/cef_browser_process_handler.rs index 49cc9e327b1..b4eec4be4de 100644 --- a/ports/cef/interfaces/cef_browser_process_handler.rs +++ b/ports/cef/interfaces/cef_browser_process_handler.rs @@ -95,7 +95,8 @@ pub struct _cef_browser_process_handler_t { this: *mut cef_browser_process_handler_t) -> *mut interfaces::cef_print_handler_t>, // - // Called when the application should call cef_do_message_loop_work() + // Called when the application should call cef_do_message_loop_work(). May be + // called from a thread. // pub on_work_available: Option ()>, @@ -261,7 +262,8 @@ impl CefBrowserProcessHandler { } // - // Called when the application should call cef_do_message_loop_work() + // Called when the application should call cef_do_message_loop_work(). May be + // called from a thread. // pub fn on_work_available(&self) -> () { if self.c_object.is_null() || diff --git a/ports/cef/interfaces/cef_command_line.rs b/ports/cef/interfaces/cef_command_line.rs index 53674ef25ba..d8926bf76c1 100644 --- a/ports/cef/interfaces/cef_command_line.rs +++ b/ports/cef/interfaces/cef_command_line.rs @@ -109,7 +109,7 @@ pub struct _cef_command_line_t { // array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* } // pub get_argv: Option ()>, + argv: &types::cef_string_list_t) -> ()>, // // Constructs and returns the represented command line string. Use this @@ -183,7 +183,7 @@ pub struct _cef_command_line_t { // Get the remaining command line arguments. // pub get_arguments: Option ()>, + arguments: &types::cef_string_list_t) -> ()>, // // Add an argument to the end of the command line. @@ -392,7 +392,7 @@ impl CefCommandLine { // Retrieve the original command line string as a vector of strings. The argv // array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* } // - pub fn get_argv(&self, argv: Vec) -> () { + pub fn get_argv(&self, argv: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -572,7 +572,7 @@ impl CefCommandLine { // // Get the remaining command line arguments. // - pub fn get_arguments(&self, arguments: Vec) -> () { + pub fn get_arguments(&self, arguments: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_context_menu_handler.rs b/ports/cef/interfaces/cef_context_menu_handler.rs index dedb9fd5c64..27373d33eab 100644 --- a/ports/cef/interfaces/cef_context_menu_handler.rs +++ b/ports/cef/interfaces/cef_context_menu_handler.rs @@ -403,7 +403,7 @@ pub struct _cef_context_menu_params_t { // pub get_dictionary_suggestions: Option libc::c_int>, + suggestions: &types::cef_string_list_t) -> libc::c_int>, // // Returns true (1) if the context menu was invoked on an editable node. @@ -746,7 +746,7 @@ impl CefContextMenuParams { // is one. // pub fn get_dictionary_suggestions(&self, - suggestions: Vec) -> libc::c_int { + suggestions: &Vec) -> libc::c_int { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_cookie.rs b/ports/cef/interfaces/cef_cookie.rs index 1b1090e9499..a41e7dff879 100644 --- a/ports/cef/interfaces/cef_cookie.rs +++ b/ports/cef/interfaces/cef_cookie.rs @@ -64,7 +64,7 @@ pub struct _cef_cookie_manager_t { // Must be called before any cookies are accessed. // pub set_supported_schemes: Option ()>, // @@ -227,7 +227,7 @@ impl CefCookieManager { // executed asnychronously on the IO thread after the change has been applied. // Must be called before any cookies are accessed. // - pub fn set_supported_schemes(&self, schemes: Vec, + pub fn set_supported_schemes(&self, schemes: &Vec, callback: interfaces::CefCompletionCallback) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { diff --git a/ports/cef/interfaces/cef_dialog_handler.rs b/ports/cef/interfaces/cef_dialog_handler.rs index c64634e061e..d31ffc442c6 100644 --- a/ports/cef/interfaces/cef_dialog_handler.rs +++ b/ports/cef/interfaces/cef_dialog_handler.rs @@ -65,7 +65,7 @@ pub struct _cef_file_dialog_callback_t { // pub cont: Option ()>, + file_paths: &types::cef_string_list_t) -> ()>, // // Cancel the file selection. @@ -165,7 +165,7 @@ impl CefFileDialogCallback { // value is treated the same as calling cancel(). // pub fn cont(&self, selected_accept_filter: libc::c_int, - file_paths: Vec) -> () { + file_paths: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -251,7 +251,7 @@ pub struct _cef_dialog_handler_t { browser: *mut interfaces::cef_browser_t, mode: types::cef_file_dialog_mode_t, title: *const types::cef_string_t, default_file_path: *const types::cef_string_t, - accept_filters: types::cef_string_list_t, + accept_filters: &types::cef_string_list_t, selected_accept_filter: libc::c_int, callback: *mut interfaces::cef_file_dialog_callback_t) -> libc::c_int>, @@ -357,7 +357,7 @@ impl CefDialogHandler { // pub fn on_file_dialog(&self, browser: interfaces::CefBrowser, mode: types::cef_file_dialog_mode_t, title: &[u16], - default_file_path: &[u16], accept_filters: Vec, + default_file_path: &[u16], accept_filters: &Vec, selected_accept_filter: libc::c_int, callback: interfaces::CefFileDialogCallback) -> libc::c_int { if self.c_object.is_null() || diff --git a/ports/cef/interfaces/cef_display_handler.rs b/ports/cef/interfaces/cef_display_handler.rs index 1221e0e3889..0b9eae298c8 100644 --- a/ports/cef/interfaces/cef_display_handler.rs +++ b/ports/cef/interfaces/cef_display_handler.rs @@ -77,7 +77,7 @@ pub struct _cef_display_handler_t { // pub on_favicon_urlchange: Option ()>, + icon_urls: &types::cef_string_list_t) -> ()>, // // Called when the browser is about to display a tooltip. |text| contains the @@ -234,7 +234,7 @@ impl CefDisplayHandler { // Called when the page icon changes. // pub fn on_favicon_urlchange(&self, browser: interfaces::CefBrowser, - icon_urls: Vec) -> () { + icon_urls: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_drag_data.rs b/ports/cef/interfaces/cef_drag_data.rs index 2c4d3ec1349..eefaa1f2374 100644 --- a/ports/cef/interfaces/cef_drag_data.rs +++ b/ports/cef/interfaces/cef_drag_data.rs @@ -149,7 +149,7 @@ pub struct _cef_drag_data_t { // window. // pub get_file_names: Option libc::c_int>, + names: &types::cef_string_list_t) -> libc::c_int>, // // Set the link URL that is being dragged. @@ -499,7 +499,7 @@ impl CefDragData { // Retrieve the list of file names that are being dragged into the browser // window. // - pub fn get_file_names(&self, names: Vec) -> libc::c_int { + pub fn get_file_names(&self, names: &Vec) -> libc::c_int { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_ssl_info.rs b/ports/cef/interfaces/cef_ssl_info.rs index d2cfcba7c59..27108f472a7 100644 --- a/ports/cef/interfaces/cef_ssl_info.rs +++ b/ports/cef/interfaces/cef_ssl_info.rs @@ -97,20 +97,20 @@ pub struct _cef_sslcert_principal_t { // pub get_street_addresses: Option ()>, + addresses: &types::cef_string_list_t) -> ()>, // // Retrieve the list of organization names. // pub get_organization_names: Option ( + this: *mut cef_sslcert_principal_t, names: &types::cef_string_list_t) -> ( )>, // // Retrieve the list of organization unit names. // pub get_organization_unit_names: Option ( + this: *mut cef_sslcert_principal_t, names: &types::cef_string_list_t) -> ( )>, // @@ -118,7 +118,7 @@ pub struct _cef_sslcert_principal_t { // pub get_domain_components: Option ()>, + components: &types::cef_string_list_t) -> ()>, // // The reference count. This will only be present for Rust instances! @@ -288,7 +288,7 @@ impl CefSSLCertPrincipal { // // Retrieve the list of street addresses. // - pub fn get_street_addresses(&self, addresses: Vec) -> () { + pub fn get_street_addresses(&self, addresses: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -304,7 +304,7 @@ impl CefSSLCertPrincipal { // // Retrieve the list of organization names. // - pub fn get_organization_names(&self, names: Vec) -> () { + pub fn get_organization_names(&self, names: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -320,7 +320,7 @@ impl CefSSLCertPrincipal { // // Retrieve the list of organization unit names. // - pub fn get_organization_unit_names(&self, names: Vec) -> () { + pub fn get_organization_unit_names(&self, names: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") @@ -336,7 +336,7 @@ impl CefSSLCertPrincipal { // // Retrieve the list of domain components. // - pub fn get_domain_components(&self, components: Vec) -> () { + pub fn get_domain_components(&self, components: &Vec) -> () { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_v8.rs b/ports/cef/interfaces/cef_v8.rs index efe234b92a3..eed48cc7a04 100644 --- a/ports/cef/interfaces/cef_v8.rs +++ b/ports/cef/interfaces/cef_v8.rs @@ -1364,7 +1364,7 @@ pub struct _cef_v8value_t { // based keys will also be returned as strings. // pub get_keys: Option libc::c_int>, + keys: &types::cef_string_list_t) -> libc::c_int>, // // Sets the user data for this object and returns true (1) on success. Returns @@ -2117,7 +2117,7 @@ impl CefV8Value { // Read the keys for the object's values into the specified vector. Integer- // based keys will also be returned as strings. // - pub fn get_keys(&self, keys: Vec) -> libc::c_int { + pub fn get_keys(&self, keys: &Vec) -> libc::c_int { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/interfaces/cef_values.rs b/ports/cef/interfaces/cef_values.rs index 398ae37b782..8a9234b4e34 100644 --- a/ports/cef/interfaces/cef_values.rs +++ b/ports/cef/interfaces/cef_values.rs @@ -1099,7 +1099,7 @@ pub struct _cef_dictionary_value_t { // Reads all keys for this dictionary into the specified vector. // pub get_keys: Option libc::c_int>, + keys: &types::cef_string_list_t) -> libc::c_int>, // // Removes the value at the specified key. Returns true (1) is the value was @@ -1489,7 +1489,7 @@ impl CefDictionaryValue { // // Reads all keys for this dictionary into the specified vector. // - pub fn get_keys(&self, keys: Vec) -> libc::c_int { + pub fn get_keys(&self, keys: &Vec) -> libc::c_int { if self.c_object.is_null() || self.c_object as usize == mem::POST_DROP_USIZE { panic!("called a CEF method on a null object") diff --git a/ports/cef/string_list.rs b/ports/cef/string_list.rs index b41532731f8..a9a2dfc5252 100644 --- a/ports/cef/string_list.rs +++ b/ports/cef/string_list.rs @@ -4,12 +4,14 @@ use libc::{c_int}; use std::mem; -use string::{cef_string_userfree_utf16_alloc,cef_string_userfree_utf16_free,cef_string_utf16_set}; +use std::slice; +use string::cef_string_utf16_set; use types::{cef_string_list_t,cef_string_t}; +use rustc_unicode::str::Utf16Encoder; -fn string_list_to_vec(lt: *mut cef_string_list_t) -> *mut Vec<*mut cef_string_t> { - lt as *mut Vec<*mut cef_string_t> +fn string_list_to_vec(lt: *mut cef_string_list_t) -> *mut Vec { + lt as *mut Vec } //cef_string_list @@ -17,7 +19,7 @@ fn string_list_to_vec(lt: *mut cef_string_list_t) -> *mut Vec<*mut cef_string_t> #[no_mangle] pub extern "C" fn cef_string_list_alloc() -> *mut cef_string_list_t { unsafe { - let lt: Box> = box vec!(); + let lt: Box> = box vec!(); mem::transmute(lt) } } @@ -36,9 +38,7 @@ pub extern "C" fn cef_string_list_append(lt: *mut cef_string_list_t, value: *con unsafe { if lt.is_null() { return; } let v = string_list_to_vec(lt); - let cs = cef_string_userfree_utf16_alloc(); - cef_string_utf16_set(mem::transmute((*value).str), (*value).length, cs, 1); - (*v).push(cs); + (*v).push(String::from_utf16(slice::from_raw_parts((*value).str, (*value).length as usize)).unwrap()); } } @@ -48,8 +48,9 @@ pub extern "C" fn cef_string_list_value(lt: *mut cef_string_list_t, index: c_int if index < 0 || lt.is_null() { return 0; } let v = string_list_to_vec(lt); if index as usize > (*v).len() - 1 { return 0; } - let cs = (*v)[index as usize]; - cef_string_utf16_set(mem::transmute((*cs).str), (*cs).length, value, 1) + let ref string = (*v)[index as usize]; + let utf16_chars: Vec = Utf16Encoder::new(string.chars()).collect(); + cef_string_utf16_set(mem::transmute(utf16_chars.as_ptr()), utf16_chars.len() as u64, value, 1) } } @@ -58,12 +59,7 @@ pub extern "C" fn cef_string_list_clear(lt: *mut cef_string_list_t) { unsafe { if lt.is_null() { return; } let v = string_list_to_vec(lt); - if (*v).len() == 0 { return; } - let mut cs; - while (*v).len() != 0 { - cs = (*v).pop(); - cef_string_userfree_utf16_free(cs.unwrap()); - } + (*v).clear(); } } @@ -71,7 +67,7 @@ pub extern "C" fn cef_string_list_clear(lt: *mut cef_string_list_t) { pub extern "C" fn cef_string_list_free(lt: *mut cef_string_list_t) { unsafe { if lt.is_null() { return; } - let v: Box> = mem::transmute(lt); + let v: Box> = mem::transmute(lt); cef_string_list_clear(lt); drop(v); } @@ -82,10 +78,7 @@ pub extern "C" fn cef_string_list_copy(lt: *mut cef_string_list_t) -> *mut cef_s unsafe { if lt.is_null() { return 0 as *mut cef_string_list_t; } let v = string_list_to_vec(lt); - let lt2 = cef_string_list_alloc(); - for cs in (*v).iter() { - cef_string_list_append(lt2, mem::transmute((*cs))); - } - lt2 + let copy = (*v).clone(); + mem::transmute(box copy) } } diff --git a/ports/cef/types.rs b/ports/cef/types.rs index 38accd438e1..38ea11cfc56 100644 --- a/ports/cef/types.rs +++ b/ports/cef/types.rs @@ -15,7 +15,7 @@ pub use self::cef_rect as cef_rect_t; pub enum cef_string_map_t {} pub enum cef_string_multimap_t {} -pub enum cef_string_list_t {} +pub type cef_string_list_t = Vec; pub enum cef_text_input_context_t {} pub enum cef_event_handle_t {} diff --git a/ports/cef/window.rs b/ports/cef/window.rs index 8af65a1c4e7..94c073abcc3 100644 --- a/ports/cef/window.rs +++ b/ports/cef/window.rs @@ -316,8 +316,16 @@ impl WindowMethods for Window { } } + fn set_favicon(&self, url: Url) { + let browser = self.cef_browser.borrow(); + let browser = match *browser { + None => return, + Some(ref browser) => browser, + }; + browser.downcast().favicons.borrow_mut().push(url.to_string().clone()); + } + fn load_start(&self, back: bool, forward: bool) { - // FIXME(pcwalton): The status code 200 is a lie. let browser = self.cef_browser.borrow(); let browser = match *browser { None => return, @@ -326,6 +334,7 @@ impl WindowMethods for Window { browser.downcast().loading.set(true); browser.downcast().back.set(back); browser.downcast().forward.set(forward); + browser.downcast().favicons.borrow_mut().clear(); if check_ptr_exist!(browser.get_host().get_client(), get_load_handler) && check_ptr_exist!(browser.get_host().get_client().get_load_handler(), on_loading_state_change) { browser.get_host() @@ -378,6 +387,18 @@ impl WindowMethods for Window { } } + fn head_parsed(&self) { + let browser = self.cef_browser.borrow(); + let browser = match *browser { + None => return, + Some(ref browser) => browser, + }; + if check_ptr_exist!(browser.get_host().get_client(), get_display_handler) && + check_ptr_exist!(browser.get_host().get_client().get_display_handler(), on_favicon_urlchange) { + browser.get_host().get_client().get_display_handler().on_favicon_urlchange((*browser).clone(), &browser.downcast().favicons.borrow()); + } + } + fn set_page_title(&self, string: Option) { let browser = self.cef_browser.borrow(); let browser = match *browser { diff --git a/ports/cef/wrappers.rs b/ports/cef/wrappers.rs index 2cc1d48fe63..dcdc686d9e5 100644 --- a/ports/cef/wrappers.rs +++ b/ports/cef/wrappers.rs @@ -135,7 +135,6 @@ cef_noop_wrapper!(*mut cef_jsdialog_handler_t); cef_noop_wrapper!(*mut cef_keyboard_handler_t); cef_noop_wrapper!(*mut cef_load_handler_t); cef_noop_wrapper!(*mut cef_request_handler_t); -cef_noop_wrapper!(*mut cef_string_list_t); cef_noop_wrapper!(*mut cef_string_utf16); cef_noop_wrapper!(c_int); cef_noop_wrapper!(CefApp); @@ -185,10 +184,10 @@ cef_noop_wrapper!(f64); cef_noop_wrapper!(i64); cef_noop_wrapper!(u32); cef_noop_wrapper!(u64); +cef_noop_wrapper!(cef_string_list_t); cef_unimplemented_wrapper!(*const *mut cef_v8value_t, *const CefV8Value); cef_unimplemented_wrapper!(*mut *mut cef_post_data_element_t, *mut CefPostDataElement); -cef_unimplemented_wrapper!(cef_string_list_t, Vec); cef_unimplemented_wrapper!(cef_string_map_t, HashMap); cef_unimplemented_wrapper!(cef_string_multimap_t, HashMap>); cef_unimplemented_wrapper!(cef_string_t, String); @@ -293,3 +292,11 @@ impl<'a> CefWrap for &'a mut String { } } +impl<'a> CefWrap<&'a cef_string_list_t> for &'a cef_string_list_t { + fn to_c(stringlist: &'a cef_string_list_t) -> &'a cef_string_list_t { + stringlist + } + unsafe fn to_rust(_: &'a cef_string_list_t) -> &'a cef_string_list_t { + panic!("unimplemented CEF type conversion: cef_string_t"); + } +} diff --git a/ports/glutin/window.rs b/ports/glutin/window.rs index ff3f53724dd..04a4276f856 100644 --- a/ports/glutin/window.rs +++ b/ports/glutin/window.rs @@ -515,6 +515,9 @@ impl WindowMethods for Window { fn load_error(&self, _: NetError, _: String) { } + fn head_parsed(&self) { + } + /// Has no effect on Android. fn set_cursor(&self, c: Cursor) { use glutin::MouseCursor; @@ -559,6 +562,9 @@ impl WindowMethods for Window { self.window.set_cursor(glutin_cursor); } + fn set_favicon(&self, _: Url) { + } + fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool { true } @@ -703,10 +709,15 @@ impl WindowMethods for Window { } fn load_error(&self, _: NetError, _: String) { } + fn head_parsed(&self) { + } fn set_cursor(&self, _: Cursor) { } + fn set_favicon(&self, _: Url) { + } + fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool { true } diff --git a/ports/gonk/src/window.rs b/ports/gonk/src/window.rs index a2c9f6b020a..f874545bd20 100644 --- a/ports/gonk/src/window.rs +++ b/ports/gonk/src/window.rs @@ -812,6 +812,9 @@ impl WindowMethods for Window { fn load_error(&self, _: NetError, _: String) { } + fn head_parsed(&self) { + } + fn hidpi_factor(&self) -> ScaleFactor { ScaleFactor::new(1.0) } @@ -838,6 +841,9 @@ impl WindowMethods for Window { fn set_cursor(&self, _: Cursor) { } + fn set_favicon(&self, _: Url) { + } + fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool { true }