Bug 1382136 - Part 1: Implement clone_content method. r?hiro
MozReview-Commit-ID: 4FpCQ6u5nMe
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -914,8 +914,21 @@ impl<T> Rect<T> where T: GeckoStyleCoord
T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"),
T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert")
)
)
}
}
+
+/// Convert to String from given chars pointer.
+pub unsafe fn string_from_chars_pointer(p: *const u16) -> String {
+ use std::slice;
+ let mut length = 0;
+ let mut iter = p;
+ while *iter != 0 {
+ length += 1;
+ iter = iter.offset(1);
+ }
+ let char_vec = slice::from_raw_parts(p, length as usize);
+ String::from_utf16_lossy(char_vec)
+}
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -9,17 +9,17 @@ use app_units::Au;
use context::QuirksMode;
use cssparser::{CssStringWriter, Parser, RGBA, Token, BasicParseError};
use euclid::ScaleFactor;
use euclid::Size2D;
use font_metrics::get_metrics_provider_for_product;
use gecko::values::convert_nscolor_to_rgba;
use gecko_bindings::bindings;
use gecko_bindings::structs;
-use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit, nsStringBuffer};
+use gecko_bindings::structs::{nsCSSKeyword, nsCSSProps_KTableEntry, nsCSSValue, nsCSSUnit};
use gecko_bindings::structs::{nsMediaExpression_Range, nsMediaFeature};
use gecko_bindings::structs::{nsMediaFeature_ValueType, nsMediaFeature_RangeType, nsMediaFeature_RequirementFlags};
use gecko_bindings::structs::{nsPresContext, RawGeckoPresContextOwned};
use gecko_bindings::structs::nsIAtom;
use media_queries::MediaType;
use parser::ParserContext;
use properties::{ComputedValues, StyleBuilder};
use properties::longhands::font_size;
@@ -289,29 +289,16 @@ impl ToCss for Resolution {
match *self {
Resolution::Dpi(v) => write!(dest, "{}dpi", v),
Resolution::Dppx(v) => write!(dest, "{}dppx", v),
Resolution::Dpcm(v) => write!(dest, "{}dpcm", v),
}
}
}
-unsafe fn string_from_ns_string_buffer(buffer: *const nsStringBuffer) -> String {
- use std::slice;
- debug_assert!(!buffer.is_null());
- let data = buffer.offset(1) as *const u16;
- let mut length = 0;
- let mut iter = data;
- while *iter != 0 {
- length += 1;
- iter = iter.offset(1);
- }
- String::from_utf16_lossy(slice::from_raw_parts(data, length))
-}
-
/// A value found or expected in a media expression.
#[derive(PartialEq, Debug, Clone)]
pub enum MediaExpressionValue {
/// A length.
Length(specified::Length),
/// A (non-negative) integer.
Integer(u32),
/// A floating point value.
@@ -329,16 +316,18 @@ pub enum MediaExpressionValue {
/// An identifier.
///
/// TODO(emilio): Maybe atomize?
Ident(String),
}
impl MediaExpressionValue {
fn from_css_value(for_expr: &Expression, css_value: &nsCSSValue) -> Option<Self> {
+ use gecko::conversions::string_from_chars_pointer;
+
// NB: If there's a null value, that means that we don't support the
// feature.
if css_value.mUnit == nsCSSUnit::eCSSUnit_Null {
return None;
}
match for_expr.feature.mValueType {
nsMediaFeature_ValueType::eLength => {
@@ -367,17 +356,19 @@ impl MediaExpressionValue {
}
nsMediaFeature_ValueType::eEnumerated => {
let value = css_value.integer_unchecked() as i16;
Some(MediaExpressionValue::Enumerated(value))
}
nsMediaFeature_ValueType::eIdent => {
debug_assert!(css_value.mUnit == nsCSSUnit::eCSSUnit_Ident);
let string = unsafe {
- string_from_ns_string_buffer(*css_value.mValue.mString.as_ref())
+ let buffer = *css_value.mValue.mString.as_ref();
+ debug_assert!(!buffer.is_null());
+ string_from_chars_pointer(buffer.offset(1) as *const u16)
};
Some(MediaExpressionValue::Ident(string))
}
nsMediaFeature_ValueType::eIntRatio => {
let array = unsafe { css_value.array_unchecked() };
debug_assert_eq!(array.len(), 2);
let first = array[0].integer_unchecked();
let second = array[1].integer_unchecked();
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -5594,16 +5594,90 @@ clip-path
Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko)
}
}
pub fn reset_content(&mut self, other: &Self) {
self.copy_content_from(other)
}
+ pub fn clone_content(&self) -> longhands::content::computed_value::T {
+ use gecko::conversions::string_from_chars_pointer;
+ use gecko_bindings::structs::nsStyleContentType::*;
+ use properties::longhands::content::computed_value::{T, ContentItem};
+ use values::generics::CounterStyleOrNone;
+ use values::specified::url::SpecifiedUrl;
+ use values::specified::Attr;
+
+ if self.gecko.mContents.is_empty() {
+ return T::Normal;
+ }
+
+ if self.gecko.mContents.len() == 1 &&
+ self.gecko.mContents[0].mType == eStyleContentType_AltContent {
+ return T::MozAltContent;
+ }
+
+ T::Items(
+ self.gecko.mContents.iter().map(|gecko_content| {
+ match gecko_content.mType {
+ eStyleContentType_OpenQuote => ContentItem::OpenQuote,
+ eStyleContentType_CloseQuote => ContentItem::CloseQuote,
+ eStyleContentType_NoOpenQuote => ContentItem::NoOpenQuote,
+ eStyleContentType_NoCloseQuote => ContentItem::NoCloseQuote,
+ eStyleContentType_String => {
+ let gecko_chars = unsafe { gecko_content.mContent.mString.as_ref() };
+ let string = unsafe { string_from_chars_pointer(*gecko_chars) };
+ ContentItem::String(string)
+ },
+ eStyleContentType_Attr => {
+ let gecko_chars = unsafe { gecko_content.mContent.mString.as_ref() };
+ let string = unsafe { string_from_chars_pointer(*gecko_chars) };
+ let (namespace, attribute) =
+ match string.find('|') {
+ None => (None, string),
+ Some(index) => {
+ let (_, val) = string.split_at(index);
+ // FIXME: We should give NamespaceId as well to make Attr
+ // struct. However, there is no field for it in Gecko.
+ debug_assert!(false, "Attr with namespace does not support yet");
+ (None, val.to_string())
+ }
+ };
+ ContentItem::Attr(Attr { namespace, attribute })
+ },
+ eStyleContentType_Counter | eStyleContentType_Counters => {
+ let gecko_function =
+ unsafe { &**gecko_content.mContent.mCounters.as_ref() };
+ let ident = gecko_function.mIdent.to_string();
+ let style =
+ CounterStyleOrNone::from_gecko_value(&gecko_function.mCounterStyle);
+ if gecko_content.mType == eStyleContentType_Counter {
+ ContentItem::Counter(ident, style)
+ } else {
+ let separator = gecko_function.mSeparator.to_string();
+ ContentItem::Counters(ident, separator, style)
+ }
+ },
+ eStyleContentType_Image => {
+ unsafe {
+ let gecko_image_request =
+ unsafe { &**gecko_content.mContent.mImage.as_ref() };
+ ContentItem::Url(
+ SpecifiedUrl::from_image_request(gecko_image_request)
+ .expect("mContent could not convert to SpecifiedUrl")
+ )
+ }
+ },
+ x => panic!("Found unexpected value in style struct for content property: {:?}", x),
+ }
+ }).collect()
+ )
+ }
+
% for counter_property in ["Increment", "Reset"]:
pub fn set_counter_${counter_property.lower()}(&mut self, v: longhands::counter_increment::computed_value::T) {
unsafe {
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko,
v.0.len() as u32);
for (i, (name, value)) in v.0.into_iter().enumerate() {
self.gecko.m${counter_property}s[i].mCounter.assign(name.0.as_slice());
self.gecko.m${counter_property}s[i].mValue = value;