-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
url.rs
169 lines (146 loc) · 5.98 KB
/
url.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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/. */
//! Common handling for the specified value CSS url() values.
use gecko_bindings::structs::{ServoBundledURI, URLExtraData};
use gecko_bindings::structs::mozilla::css::URLValueData;
use gecko_bindings::structs::root::{nsStyleImageRequest, RustString};
use gecko_bindings::structs::root::mozilla::css::ImageValue;
use gecko_bindings::sugar::refptr::RefPtr;
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use parser::ParserContext;
use servo_arc::{Arc, RawOffsetArc};
use std::fmt::{self, Write};
use std::mem;
use style_traits::{CssWriter, ToCss, ParseError};
/// A specified url() value for gecko. Gecko does not eagerly resolve SpecifiedUrls.
#[derive(Clone, Debug, PartialEq)]
pub struct SpecifiedUrl {
/// The URL in unresolved string form.
///
/// Refcounted since cloning this should be cheap and data: uris can be
/// really large.
serialization: Arc<String>,
/// The URL extra data.
pub extra_data: RefPtr<URLExtraData>,
/// Cache ImageValue, if any, so that we can reuse it while rematching a
/// a property with this specified url value.
pub image_value: Option<RefPtr<ImageValue>>,
}
trivial_to_computed_value!(SpecifiedUrl);
impl SpecifiedUrl {
/// Try to parse a URL from a string value that is a valid CSS token for a
/// URL.
///
/// Returns `Err` in the case that extra_data is incomplete.
pub fn parse_from_string<'a>(url: String,
context: &ParserContext)
-> Result<Self, ParseError<'a>> {
Ok(SpecifiedUrl {
serialization: Arc::new(url),
extra_data: context.url_data.clone(),
image_value: None,
})
}
/// Returns true if the URL is definitely invalid. We don't eagerly resolve
/// URLs in gecko, so we just return false here.
/// use its |resolved| status.
pub fn is_invalid(&self) -> bool {
false
}
/// Convert from URLValueData to SpecifiedUrl.
pub unsafe fn from_url_value_data(url: &URLValueData)
-> Result<SpecifiedUrl, ()> {
Ok(SpecifiedUrl {
serialization: if url.mUsingRustString {
let arc_type = url.mStrings.mRustString.as_ref()
as *const _ as
*const RawOffsetArc<String>;
Arc::from_raw_offset((*arc_type).clone())
} else {
Arc::new(url.mStrings.mString.as_ref().to_string())
},
extra_data: url.mExtraData.to_safe(),
image_value: None,
})
}
/// Convert from nsStyleImageRequest to SpecifiedUrl.
pub unsafe fn from_image_request(image_request: &nsStyleImageRequest) -> Result<SpecifiedUrl, ()> {
if image_request.mImageValue.mRawPtr.is_null() {
return Err(());
}
let image_value = image_request.mImageValue.mRawPtr.as_ref().unwrap();
let ref url_value_data = image_value._base;
let mut result = try!(Self::from_url_value_data(url_value_data));
result.build_image_value();
Ok(result)
}
/// Returns true if this URL looks like a fragment.
/// See https://drafts.csswg.org/css-values/#local-urls
pub fn is_fragment(&self) -> bool {
self.as_str().chars().next().map_or(false, |c| c == '#')
}
/// Return the resolved url as string, or the empty string if it's invalid.
///
/// FIXME(bholley): This returns the unresolved URL while the servo version
/// returns the resolved URL.
pub fn as_str(&self) -> &str {
&*self.serialization
}
/// Little helper for Gecko's ffi.
pub fn as_slice_components(&self) -> (*const u8, usize) {
(self.serialization.as_str().as_ptr(), self.serialization.as_str().len())
}
/// Create a bundled URI suitable for sending to Gecko
/// to be constructed into a css::URLValue
pub fn for_ffi(&self) -> ServoBundledURI {
let (ptr, len) = self.as_slice_components();
ServoBundledURI {
mURLString: ptr,
mURLStringLength: len as u32,
mExtraData: self.extra_data.get(),
}
}
/// Build and carry an image value on request.
pub fn build_image_value(&mut self) {
use gecko_bindings::bindings::Gecko_ImageValue_Create;
debug_assert_eq!(self.image_value, None);
self.image_value = {
unsafe {
let arc_offset = Arc::into_raw_offset(self.serialization.clone());
let ptr = Gecko_ImageValue_Create(
self.for_ffi(),
mem::transmute::<_, RawOffsetArc<RustString>>(arc_offset));
// We do not expect Gecko_ImageValue_Create returns null.
debug_assert!(!ptr.is_null());
Some(RefPtr::from_addrefed(ptr))
}
}
}
}
impl ToCss for SpecifiedUrl {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str("url(")?;
self.serialization.to_css(dest)?;
dest.write_str(")")
}
}
impl MallocSizeOf for SpecifiedUrl {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
use gecko_bindings::bindings::Gecko_ImageValue_SizeOfIncludingThis;
let mut n = 0;
// XXX: measure `serialization` once bug 1397971 lands
// We ignore `extra_data`, because RefPtr is tricky, and there aren't
// many of them in practise (sharing is common).
if let Some(ref image_value) = self.image_value {
// Although this is a RefPtr, this is the primary reference because
// SpecifiedUrl is responsible for creating the image_value. So we
// measure unconditionally here.
n += unsafe { Gecko_ImageValue_SizeOfIncludingThis(image_value.clone().get()) };
}
n
}
}