Bug 1466963: Provide a before-mutation closure to C++. r=xidorn,smaug

MozReview-Commit-ID: H2jwIeZoiBZ
This commit is contained in:
Emilio Cobos Álvarez 2018-06-06 00:04:39 +02:00
parent f33e5c0e87
commit 0fbd75e65f
9 changed files with 127 additions and 38 deletions

View File

@ -2663,7 +2663,8 @@ CreateDeclarationForServo(nsCSSPropertyID aProperty,
data,
ParsingMode::Default,
aDocument->GetCompatibilityMode(),
aDocument->CSSLoader());
aDocument->CSSLoader(),
{ });
}
return servoDeclarations.forget();

View File

@ -1202,7 +1202,8 @@ MappedAttrParser::ParseMappedAttrValue(nsAtom* aMappedAttrName,
mElement->NodePrincipal());
changed = Servo_DeclarationBlock_SetPropertyById(
mDecl->Raw(), propertyID, &value, false, data,
ParsingMode::AllowUnitlessLength, mElement->OwnerDoc()->GetCompatibilityMode(), mLoader);
ParsingMode::AllowUnitlessLength,
mElement->OwnerDoc()->GetCompatibilityMode(), mLoader, { });
if (changed) {
// The normal reporting of use counters by the nsCSSParser won't happen

View File

@ -207,18 +207,20 @@ public:
}
// Returns whether the property was removed.
bool RemoveProperty(const nsAString& aProperty)
bool RemoveProperty(const nsAString& aProperty,
DeclarationBlockMutationClosure aClosure = { })
{
AssertMutable();
NS_ConvertUTF16toUTF8 property(aProperty);
return Servo_DeclarationBlock_RemoveProperty(mRaw, &property);
return Servo_DeclarationBlock_RemoveProperty(mRaw, &property, aClosure);
}
// Returns whether the property was removed.
bool RemovePropertyByID(nsCSSPropertyID aProperty)
bool RemovePropertyByID(nsCSSPropertyID aProperty,
DeclarationBlockMutationClosure aClosure = { })
{
AssertMutable();
return Servo_DeclarationBlock_RemovePropertyById(mRaw, aProperty);
return Servo_DeclarationBlock_RemovePropertyById(mRaw, aProperty, aClosure);
}
private:

View File

@ -510,6 +510,12 @@ SERVO_BINDING_FUNC(Servo_AnimationValue_Compute,
ComputedStyleBorrowed style,
RawServoStyleSetBorrowed raw_data)
// There's no reason we couldn't expose more stuff here, but GetCssText is
// pretty much all we'd ever want.
SERVO_BINDING_FUNC(Servo_UnlockedDeclarationBlock_GetCssText, void,
const RawServoUnlockedDeclarationBlock* declarations,
nsAString* result)
// Style attribute
SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
const nsACString* data,
@ -552,7 +558,8 @@ SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
RawGeckoURLExtraData* data,
mozilla::ParsingMode parsing_mode,
nsCompatibility quirks_mode,
mozilla::css::Loader* loader)
mozilla::css::Loader* loader,
DeclarationBlockMutationClosure)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyToAnimationValue, bool,
RawServoDeclarationBlockBorrowed declarations,
RawServoAnimationValueBorrowed animation_value)
@ -563,13 +570,16 @@ SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetPropertyById, bool,
RawGeckoURLExtraData* data,
mozilla::ParsingMode parsing_mode,
nsCompatibility quirks_mode,
mozilla::css::Loader* loader)
mozilla::css::Loader* loader,
DeclarationBlockMutationClosure)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, bool,
RawServoDeclarationBlockBorrowed declarations,
const nsACString* property)
const nsACString* property,
DeclarationBlockMutationClosure)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemovePropertyById, bool,
RawServoDeclarationBlockBorrowed declarations,
nsCSSPropertyID property)
nsCSSPropertyID property,
DeclarationBlockMutationClosure)
SERVO_BINDING_FUNC(Servo_DeclarationBlock_HasCSSWideKeyword, bool,
RawServoDeclarationBlockBorrowed declarations,
nsCSSPropertyID property)

View File

@ -83,6 +83,22 @@ typedef nsTArray<nsCSSPropertyID> RawGeckoCSSPropertyIDList;
typedef mozilla::gfx::Float RawGeckoGfxMatrix4x4[16];
typedef mozilla::dom::StyleChildrenIterator RawGeckoStyleChildrenIterator;
// A struct which to be used as an opaque pointer to a DeclarationBlock that has
// been read.
//
// This is effectively a *const PropertyDeclarationBlock in Rust.
struct RawServoUnlockedDeclarationBlock;
// A callback that can be sent via FFI which will be invoked _right before_
// being mutated, and at most once.
struct DeclarationBlockMutationClosure
{
// The callback function, first argument is the unlocked servo declaration
// block, second is `data`.
void (*function)(const RawServoUnlockedDeclarationBlock*, void*) = nullptr;
void* data = nullptr;
};
// We have these helper types so that we can directly generate
// things like &T or Borrowed<T> on the Rust side in the function, providing
// additional safety benefits.
@ -136,7 +152,7 @@ struct MOZ_MUST_USE_TYPE ComputedStyleStrong
DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
// This is a reference to a reference of RawServoDeclarationBlock, which
// corresponds to Option<&Arc<RawServoDeclarationBlock>> in Servo side.
// corresponds to Option<&Arc<Locked<RawServoDeclarationBlock>>> in Servo side.
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
DECL_OWNED_REF_TYPE_FOR(RawServoAuthorStyles)
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoAuthorStyles)

View File

@ -210,6 +210,7 @@ whitelist-vars = [
]
whitelist-types = [
"RawGecko.*",
"DeclarationBlockMutationClosure",
"mozilla::AnimationPropertySegment",
"mozilla::AnonymousCounterStyle",
"mozilla::AtomArray",
@ -465,6 +466,8 @@ structs-types = [
"mozilla::OriginFlags",
"mozilla::UniquePtr",
"ServoRawOffsetArc",
"DeclarationBlockMutationClosure",
"RawServoUnlockedDeclarationBlock",
"nsIContent",
"nsINode",
"nsIDocument",

View File

@ -290,7 +290,7 @@ nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSPropertyID aPropID,
NS_ConvertUTF16toUTF8 value(aPropValue);
return Servo_DeclarationBlock_SetPropertyById(
decl->Raw(), aPropID, &value, aIsImportant, env.mUrlExtraData,
ParsingMode::Default, env.mCompatMode, env.mLoader);
ParsingMode::Default, env.mCompatMode, env.mLoader, /* aClosure = */ { });
});
}
@ -308,7 +308,7 @@ nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName,
NS_ConvertUTF16toUTF8 value(aPropValue);
return Servo_DeclarationBlock_SetProperty(
decl->Raw(), &property, &value, aIsImportant, env.mUrlExtraData,
ParsingMode::Default, env.mCompatMode, env.mLoader);
ParsingMode::Default, env.mCompatMode, env.mLoader, /* aClosure = */ { });
});
}

View File

@ -62,7 +62,8 @@ static void ServoSetPropertyByIdBench(const nsACString& css) {
data,
ParsingMode::Default,
eCompatibility_FullStandards,
nullptr
nullptr,
{ }
);
}
}
@ -81,7 +82,8 @@ static void ServoGetPropertyValueById() {
data,
ParsingMode::Default,
eCompatibility_FullStandards,
nullptr
nullptr,
{ }
);
for (int i = 0; i < GETPROPERTY_REPETITIONS; i++) {

View File

@ -89,7 +89,7 @@ use style::gecko_bindings::bindings::nsTimingFunctionBorrowed;
use style::gecko_bindings::bindings::nsTimingFunctionBorrowedMut;
use style::gecko_bindings::structs;
use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation};
use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{DeclarationBlockMutationClosure, Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString};
use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID};
use style::gecko_bindings::structs::{StyleSheet as DomStyleSheet, SheetLoadData, SheetLoadDataHolder};
@ -166,6 +166,21 @@ use style_traits::{CssType, CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
use super::error_reporter::ErrorReporter;
use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
trait ClosureHelper {
fn invoke(&self, decls: &PropertyDeclarationBlock);
}
impl ClosureHelper for DeclarationBlockMutationClosure {
#[inline]
fn invoke(&self, decls: &PropertyDeclarationBlock) {
if let Some(function) = self.function.as_ref() {
unsafe {
function(decls as *const _ as *const _, self.data);
}
}
}
}
/*
* For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
* the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
@ -3394,13 +3409,25 @@ pub extern "C" fn Servo_DeclarationBlock_Equals(
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetCssText(declarations: RawServoDeclarationBlockBorrowed,
result: *mut nsAString) {
pub unsafe extern "C" fn Servo_DeclarationBlock_GetCssText(
declarations: RawServoDeclarationBlockBorrowed,
result: *mut nsAString,
) {
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.to_css(unsafe { result.as_mut().unwrap() }).unwrap();
decls.to_css(&mut *result).unwrap()
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_UnlockedDeclarationBlock_GetCssText(
declarations: *const structs::RawServoUnlockedDeclarationBlock,
result: *mut nsAString,
) {
let decls = &*(declarations as *const PropertyDeclarationBlock);
decls.to_css(&mut *result).unwrap()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
declarations: RawServoDeclarationBlockBorrowed,
@ -3529,24 +3556,34 @@ fn set_property(
data: *mut URLExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: QuirksMode,
loader: *mut Loader
loader: *mut Loader,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
let mut source_declarations = SourcePropertyDeclaration::new();
let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
match parse_property_into(&mut source_declarations, property_id, value, data,
parsing_mode, quirks_mode, &reporter) {
Ok(()) => {
let importance = if is_important { Importance::Important } else { Importance::Normal };
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.extend(
source_declarations.drain(),
importance,
DeclarationSource::CssOm
)
})
},
Err(_) => false,
let result = parse_property_into(
&mut source_declarations,
property_id,
value,
data,
parsing_mode,
quirks_mode,
&reporter,
);
if result.is_err() {
return false;
}
let importance = if is_important { Importance::Important } else { Importance::Normal };
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
before_change_closure.invoke(&*decls);
decls.extend(
source_declarations.drain(),
importance,
DeclarationSource::CssOm
)
})
}
#[no_mangle]
@ -3559,6 +3596,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
declarations,
@ -3569,6 +3607,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
parsing_mode,
quirks_mode.into(),
loader,
before_change_closure,
)
}
@ -3596,6 +3635,7 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
declarations,
@ -3606,15 +3646,19 @@ pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
parsing_mode,
quirks_mode.into(),
loader,
before_change_closure,
)
}
fn remove_property(
declarations: RawServoDeclarationBlockBorrowed,
property_id: PropertyId
property_id: PropertyId,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.remove_property(&property_id, |_| {})
decls.remove_property(&property_id, |decls| {
before_change_closure.invoke(decls)
})
})
}
@ -3622,16 +3666,26 @@ fn remove_property(
pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
declarations: RawServoDeclarationBlockBorrowed,
property: *const nsACString,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
remove_property(declarations, get_property_id_from_property!(property, false))
remove_property(
declarations,
get_property_id_from_property!(property, false),
before_change_closure,
)
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
declarations: RawServoDeclarationBlockBorrowed,
property: nsCSSPropertyID
property: nsCSSPropertyID,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
remove_property(declarations, get_property_id_from_nscsspropertyid!(property, false))
remove_property(
declarations,
get_property_id_from_nscsspropertyid!(property, false),
before_change_closure,
)
}
#[no_mangle]