gecko-dev/servo/ports/geckolib/glue.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

7006 строки
226 KiB
Rust
Исходник Обычный вид История

/* 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 https://mozilla.org/MPL/2.0/. */
use super::error_reporter::ErrorReporter;
use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
use bincode::{deserialize, serialize};
use cssparser::ToCss as ParserToCss;
use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation, UnicodeRange};
servo: Merge #18452 - Overhaul MallocSizeOf and related things (from nnethercote:bug-1398737); r=jdm This patch makes the MallocSizeOf stuff in Stylo work more like the HeapSizeOf stuff already in Servo, except better. In particular, it adds deriving support for MallocSizeOf, which will make it easier to improve coverage. The patch does the following. - Combines servo/components/style/stylesheets/memory.rs and the heapsize crate into a new crate, malloc_size_of. - Forks the heapsize_derive crate, calling it malloc_size_of, so that MallocSizeOf can be derived. - Both the new crates have MIT/Apache licenses, like heapsize, in case they are incorporated into heapsize in the future. - Renames the methods within MallocSizeOf and the related traits so they are more concise. - Removes MallocSizeOfWithGuard. - Adds `derive(MallocSizeOf)` to a lot of types, in some cases replacing an equivalent or almost-equivalent hand-written implementation. - Adds stuff so that Rc/Arc can be handled properly. <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because tested on Gecko side. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 7f4cb1861b172423781a369b2decca6c65d60546 --HG-- rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of/LICENSE-MIT rename : servo/components/jstraceable_derive/Cargo.toml => servo/components/malloc_size_of_derive/Cargo.toml rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of_derive/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of_derive/LICENSE-MIT extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : a8254c4ae15901b764d918355e900a1e74d6eb03
2017-09-12 06:11:25 +03:00
use malloc_size_of::MallocSizeOfOps;
use nsstring::{nsCString, nsString};
use selectors::matching::{matches_selector, MatchingContext, MatchingMode, VisitedHandlingMode};
use selectors::{NthIndexCache, SelectorList};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
use smallvec::SmallVec;
use std::cell::RefCell;
use std::collections::BTreeSet;
use std::fmt::Write;
use std::iter;
use std::os::raw::c_void;
use std::ptr;
use style::applicable_declarations::ApplicableDeclarationBlock;
use style::author_styles::AuthorStyles;
use style::context::ThreadLocalStyleContext;
use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
use style::counter_style;
use style::data::{self, ElementStyles};
use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
use style::driver;
use style::element_state::{DocumentState, ElementState};
use style::error_reporting::{ContextualParseError, ParseErrorReporter};
use style::font_face::{self, ComputedFontStyleDescriptor, FontFaceSourceListComponent, Source};
use style::font_metrics::{get_metrics_provider_for_product, FontMetricsProvider};
use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
use style::gecko::restyle_damage::GeckoRestyleDamage;
use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
servo: Merge #13372 - Merge most of geckolib into style (from Manishearth:merge-stylo); r=emilio Fixes #13038 r? @emilio Source-Repo: https://github.com/servo/servo Source-Revision: f763eca344fa6a49f2467d9baa25044bebc41ff2 --HG-- rename : servo/ports/geckolib/binding_tools/.gitignore => servo/components/style/binding_tools/.gitignore rename : servo/ports/geckolib/binding_tools/README.md => servo/components/style/binding_tools/README.md rename : servo/ports/geckolib/binding_tools/regen.py => servo/components/style/binding_tools/regen.py rename : servo/ports/geckolib/binding_tools/regen.sh => servo/components/style/binding_tools/regen.sh rename : servo/ports/geckolib/binding_tools/regen_atoms.py => servo/components/style/binding_tools/regen_atoms.py rename : servo/ports/geckolib/binding_tools/setup_bindgen.sh => servo/components/style/binding_tools/setup_bindgen.sh rename : servo/ports/geckolib/context.rs => servo/components/style/gecko/context.rs rename : servo/components/style/gecko_conversions.rs => servo/components/style/gecko/conversions.rs rename : servo/ports/geckolib/data.rs => servo/components/style/gecko/data.rs rename : servo/components/style/generated/gecko_pseudo_element_helper.rs => servo/components/style/gecko/generated/gecko_pseudo_element_helper.rs rename : servo/components/style/gecko_selector_impl.rs => servo/components/style/gecko/selector_impl.rs rename : servo/ports/geckolib/snapshot.rs => servo/components/style/gecko/snapshot.rs rename : servo/ports/geckolib/snapshot_helpers.rs => servo/components/style/gecko/snapshot_helpers.rs rename : servo/ports/geckolib/traversal.rs => servo/components/style/gecko/traversal.rs rename : servo/components/style/gecko_values.rs => servo/components/style/gecko/values.rs rename : servo/ports/geckolib/wrapper.rs => servo/components/style/gecko/wrapper.rs rename : servo/ports/geckolib/gecko_bindings/bindings.rs => servo/components/style/gecko_bindings/bindings.rs rename : servo/ports/geckolib/gecko_bindings/lib.rs => servo/components/style/gecko_bindings/mod.rs rename : servo/ports/geckolib/gecko_bindings/ptr.rs => servo/components/style/gecko_bindings/ptr.rs rename : servo/ports/geckolib/gecko_bindings/structs_debug.rs => servo/components/style/gecko_bindings/structs_debug.rs rename : servo/ports/geckolib/gecko_bindings/structs_release.rs => servo/components/style/gecko_bindings/structs_release.rs rename : servo/ports/geckolib/gecko_bindings/sugar/mod.rs => servo/components/style/gecko_bindings/sugar/mod.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_css_shadow_array.rs => servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_style_auto_array.rs => servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs => servo/components/style/gecko_bindings/sugar/ns_style_coord.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs => servo/components/style/gecko_bindings/sugar/ns_t_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ownership.rs => servo/components/style/gecko_bindings/sugar/ownership.rs rename : servo/ports/geckolib/string_cache/lib.rs => servo/components/style/gecko_string_cache/mod.rs rename : servo/ports/geckolib/string_cache/namespace.rs => servo/components/style/gecko_string_cache/namespace.rs
2016-09-26 10:36:05 +03:00
use style::gecko::traversal::RecalcStyleOnly;
Bug 1552708 - Use cbindgen for URIs. r=heycam This doesn't clean up as much as a whole, but it's a step in the right direction. In particular, it allows us to start using simple bindings for: * Filters * Shapes and images, almost. Need to: * Get rid of the complex -moz- gradient parsing (let layout.css.simple-moz-gradient.enabled get to release). * Counters, almost. Need to: * Share the Attr representation with Gecko, by not using Option<>. * Just another variant should be enough (ContentItem::{Attr,Prefixedattr}, maybe). Which in turn allows us to remove a whole lot of bindings in followups to this. The setup changes a bit. This also removes the double pointer I complained about while reviewing the shared UA sheet patches. The old setup is: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * UrlValueSource * Arc<CssUrlData> * load id * resolved uri * CORS mode. * ... ``` The new one removes the double reference to the url data via URLValue, and looks like: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * CorsMode * LoadData * load id * resolved URI ``` The LoadData is the only mutable bit that C++ can change, and is not used from Rust. Ideally, in the future, we could just use rust-url to resolve the URL after parsing or something, and make it all immutable. Maybe. I've verified that this approach still works with the UA sheet patches (via the LoadDataSource::Lazy). The reordering of mWillChange is to avoid nsStyleDisplay from going over the size limit. We want to split it up anyway in bug 1552587, but mBinding gains a tag member, which means that we were having a bit of extra padding. One thing I want to explore is to see if we can abuse rustc's non-zero optimizations to predict the layout from C++, but that's something to explore at some other point in time and with a lot of care and help from Michael (who sits next to me and works on rustc ;)). Differential Revision: https://phabricator.services.mozilla.com/D31742
2019-05-27 14:45:12 +03:00
use style::gecko::url;
use style::gecko::wrapper::{GeckoElement, GeckoNode};
use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::nsACString;
use style::gecko_bindings::bindings::nsAString;
use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
servo: Merge #18452 - Overhaul MallocSizeOf and related things (from nnethercote:bug-1398737); r=jdm This patch makes the MallocSizeOf stuff in Stylo work more like the HeapSizeOf stuff already in Servo, except better. In particular, it adds deriving support for MallocSizeOf, which will make it easier to improve coverage. The patch does the following. - Combines servo/components/style/stylesheets/memory.rs and the heapsize crate into a new crate, malloc_size_of. - Forks the heapsize_derive crate, calling it malloc_size_of, so that MallocSizeOf can be derived. - Both the new crates have MIT/Apache licenses, like heapsize, in case they are incorporated into heapsize in the future. - Renames the methods within MallocSizeOf and the related traits so they are more concise. - Removes MallocSizeOfWithGuard. - Adds `derive(MallocSizeOf)` to a lot of types, in some cases replacing an equivalent or almost-equivalent hand-written implementation. - Adds stuff so that Rc/Arc can be handled properly. <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because tested on Gecko side. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 7f4cb1861b172423781a369b2decca6c65d60546 --HG-- rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of/LICENSE-MIT rename : servo/components/jstraceable_derive/Cargo.toml => servo/components/malloc_size_of_derive/Cargo.toml rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of_derive/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of_derive/LICENSE-MIT extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : a8254c4ae15901b764d918355e900a1e74d6eb03
2017-09-12 06:11:25 +03:00
use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
use style::gecko_bindings::structs;
use style::gecko_bindings::structs::gfxFontFeatureValueSet;
use style::gecko_bindings::structs::ipc::ByteBuf;
use style::gecko_bindings::structs::nsAtom;
use style::gecko_bindings::structs::nsCSSCounterDesc;
use style::gecko_bindings::structs::nsCSSFontDesc;
use style::gecko_bindings::structs::nsCSSPropertyID;
use style::gecko_bindings::structs::nsChangeHint;
use style::gecko_bindings::structs::nsCompatibility;
use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
use style::gecko_bindings::structs::nsTArray;
use style::gecko_bindings::structs::nsTimingFunction;
use style::gecko_bindings::structs::nsresult;
use style::gecko_bindings::structs::AtomArray;
use style::gecko_bindings::structs::CallerType;
use style::gecko_bindings::structs::CompositeOperation;
use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
use style::gecko_bindings::structs::IterationCompositeOperation;
use style::gecko_bindings::structs::Loader;
use style::gecko_bindings::structs::LoaderReusableStyleSheets;
use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
use style::gecko_bindings::structs::OriginFlags;
use style::gecko_bindings::structs::PropertyValuePair;
use style::gecko_bindings::structs::PseudoStyleType;
use style::gecko_bindings::structs::RawServoSelectorList;
use style::gecko_bindings::structs::RawServoSourceSizeList;
use style::gecko_bindings::structs::RawServoStyleRule;
servo: Merge #17953 - stylo: Measure Elements and ComputedValues (from nnethercote:bug-1383977); r=Manishearth This is for https://bugzilla.mozilla.org/show_bug.cgi?id=1383977. <!-- Please describe your changes on the following line: --> The patch provides FFI access to Gecko's SeenPtrs type from Rust, in order to record what has already been measured when measuring Arcs. (The SeenPtrs must be initialized on the Gecko side because the same table is reused for measuring all Elements within a window, because Elements can share ComputedValues.) I have confirmed with DMD that this is working correctly. The patch also introduces MallocSizeOfRepeats, which is like MallocSizeOf but takes a SizeOfState, which holds a SeenPtrs table. --- <!-- 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 #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because testing is done on mozilla-central CI. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 32e2e546ac452cf83a0fb7e1d4521df23ec5eeda --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 99f0e9952564cf20c7a2a1594d86f29c55062492
2017-08-03 03:39:15 +03:00
use style::gecko_bindings::structs::SeenPtrs;
use style::gecko_bindings::structs::ServoElementSnapshotTable;
use style::gecko_bindings::structs::ServoStyleSetSizes;
use style::gecko_bindings::structs::ServoTraversalFlags;
use style::gecko_bindings::structs::SheetLoadData;
use style::gecko_bindings::structs::SheetLoadDataHolder;
use style::gecko_bindings::structs::SheetParsingMode;
use style::gecko_bindings::structs::StyleRuleInclusion;
use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
use style::gecko_bindings::structs::URLExtraData;
use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
use style::gecko_bindings::structs::{
RawServoAnimationValue, RawServoAuthorStyles, RawServoCounterStyleRule,
RawServoDeclarationBlock, RawServoFontFaceRule, RawServoFontFeatureValuesRule,
RawServoImportRule, RawServoKeyframe, RawServoKeyframesRule, RawServoMediaList,
RawServoMediaRule, RawServoMozDocumentRule, RawServoNamespaceRule, RawServoPageRule,
RawServoSharedMemoryBuilder, RawServoStyleSet, RawServoStyleSheetContents,
RawServoSupportsRule, ServoCssRules,
};
use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
use style::gecko_bindings::sugar::ownership::{
HasBoxFFI, HasSimpleFFI, Owned, OwnedOrNull, Strong,
};
use style::gecko_bindings::sugar::refptr::RefPtr;
use style::global_style_data::{
GlobalStyleData, StyleThreadPool, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL,
};
use style::invalidation::element::restyle_hints::RestyleHint;
use style::invalidation::stylesheets::RuleChangeKind;
use style::media_queries::MediaList;
use style::parser::{self, Parse, ParserContext};
use style::profiler_label;
use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
use style::properties::{parse_one_declaration_into, parse_style_attribute};
use style::properties::{ComputedValues, CountedUnknownProperty, Importance, NonCustomPropertyId};
use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
use style::properties::{PropertyDeclarationId, ShorthandId};
use style::properties::{SourcePropertyDeclaration, StyleBuilder, UnparsedValue};
use style::rule_cache::RuleCacheConditions;
use style::rule_tree::{CascadeLevel, StrongRuleNode};
use style::selector_parser::PseudoElementCascadeType;
use style::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
use style::string_cache::{Atom, WeakAtom};
use style::style_adjuster::StyleAdjuster;
use style::stylesheets::import_rule::ImportSheet;
use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
use style::stylesheets::supports_rule::parse_condition_or_declaration;
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
use style::stylesheets::{AllowImportRules, SanitizationData, SanitizationKind};
use style::stylesheets::{CounterStyleRule, CssRule, CssRuleType, CssRules, CssRulesHelpers};
use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule};
use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule, UrlExtraData};
use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
use style::thread_state;
use style::traversal::resolve_style;
use style::traversal::DomTraversal;
use style::traversal_flags::{self, TraversalFlags};
use style::use_counters::UseCounters;
use style::values::animated::{Animate, Procedure, ToAnimatedZero};
use style::values::computed::{self, Context, ToComputedValue};
use style::values::distance::ComputeSquaredDistance;
use style::values::specified;
use style::values::specified::gecko::IntersectionObserverRootMargin;
use style::values::specified::source_size_list::SourceSizeList;
use style::values::{CustomIdent, KeyframesName};
use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
use to_shmem::SharedMemoryBuilder;
servo: Merge #13372 - Merge most of geckolib into style (from Manishearth:merge-stylo); r=emilio Fixes #13038 r? @emilio Source-Repo: https://github.com/servo/servo Source-Revision: f763eca344fa6a49f2467d9baa25044bebc41ff2 --HG-- rename : servo/ports/geckolib/binding_tools/.gitignore => servo/components/style/binding_tools/.gitignore rename : servo/ports/geckolib/binding_tools/README.md => servo/components/style/binding_tools/README.md rename : servo/ports/geckolib/binding_tools/regen.py => servo/components/style/binding_tools/regen.py rename : servo/ports/geckolib/binding_tools/regen.sh => servo/components/style/binding_tools/regen.sh rename : servo/ports/geckolib/binding_tools/regen_atoms.py => servo/components/style/binding_tools/regen_atoms.py rename : servo/ports/geckolib/binding_tools/setup_bindgen.sh => servo/components/style/binding_tools/setup_bindgen.sh rename : servo/ports/geckolib/context.rs => servo/components/style/gecko/context.rs rename : servo/components/style/gecko_conversions.rs => servo/components/style/gecko/conversions.rs rename : servo/ports/geckolib/data.rs => servo/components/style/gecko/data.rs rename : servo/components/style/generated/gecko_pseudo_element_helper.rs => servo/components/style/gecko/generated/gecko_pseudo_element_helper.rs rename : servo/components/style/gecko_selector_impl.rs => servo/components/style/gecko/selector_impl.rs rename : servo/ports/geckolib/snapshot.rs => servo/components/style/gecko/snapshot.rs rename : servo/ports/geckolib/snapshot_helpers.rs => servo/components/style/gecko/snapshot_helpers.rs rename : servo/ports/geckolib/traversal.rs => servo/components/style/gecko/traversal.rs rename : servo/components/style/gecko_values.rs => servo/components/style/gecko/values.rs rename : servo/ports/geckolib/wrapper.rs => servo/components/style/gecko/wrapper.rs rename : servo/ports/geckolib/gecko_bindings/bindings.rs => servo/components/style/gecko_bindings/bindings.rs rename : servo/ports/geckolib/gecko_bindings/lib.rs => servo/components/style/gecko_bindings/mod.rs rename : servo/ports/geckolib/gecko_bindings/ptr.rs => servo/components/style/gecko_bindings/ptr.rs rename : servo/ports/geckolib/gecko_bindings/structs_debug.rs => servo/components/style/gecko_bindings/structs_debug.rs rename : servo/ports/geckolib/gecko_bindings/structs_release.rs => servo/components/style/gecko_bindings/structs_release.rs rename : servo/ports/geckolib/gecko_bindings/sugar/mod.rs => servo/components/style/gecko_bindings/sugar/mod.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_css_shadow_array.rs => servo/components/style/gecko_bindings/sugar/ns_css_shadow_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_style_auto_array.rs => servo/components/style/gecko_bindings/sugar/ns_style_auto_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_style_coord.rs => servo/components/style/gecko_bindings/sugar/ns_style_coord.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ns_t_array.rs => servo/components/style/gecko_bindings/sugar/ns_t_array.rs rename : servo/ports/geckolib/gecko_bindings/sugar/ownership.rs => servo/components/style/gecko_bindings/sugar/ownership.rs rename : servo/ports/geckolib/string_cache/lib.rs => servo/components/style/gecko_string_cache/mod.rs rename : servo/ports/geckolib/string_cache/namespace.rs => servo/components/style/gecko_string_cache/namespace.rs
2016-09-26 10:36:05 +03:00
trait ClosureHelper {
fn invoke(&self);
}
impl ClosureHelper for DeclarationBlockMutationClosure {
#[inline]
fn invoke(&self) {
if let Some(function) = self.function.as_ref() {
unsafe { function(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
* those signatures as well, giving us a second declaration of all the Servo_* functions in this
* crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
* depend on but good enough for our purposes.
*/
// A dummy url data for where we don't pass url data in.
static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
static mut DUMMY_CHROME_URL_DATA: *mut URLExtraData = 0 as *mut _;
#[no_mangle]
pub unsafe extern "C" fn Servo_Initialize(
dummy_url_data: *mut URLExtraData,
dummy_chrome_url_data: *mut URLExtraData,
) {
use style::gecko_bindings::sugar::origin_flags;
// Pretend that we're a Servo Layout thread, to make some assertions happy.
thread_state::initialize(thread_state::ThreadState::LAYOUT);
// Perform some debug-only runtime assertions.
origin_flags::assert_flags_match();
parser::assert_parsing_mode_match();
traversal_flags::assert_traversal_flags_match();
specified::font::assert_variant_east_asian_matches();
specified::font::assert_variant_ligatures_matches();
DUMMY_URL_DATA = dummy_url_data;
DUMMY_CHROME_URL_DATA = dummy_chrome_url_data;
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Shutdown() {
DUMMY_URL_DATA = ptr::null_mut();
DUMMY_CHROME_URL_DATA = ptr::null_mut();
Stylist::shutdown();
url::shutdown();
}
#[inline(always)]
unsafe fn dummy_url_data() -> &'static UrlExtraData {
UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
}
#[allow(dead_code)]
fn is_main_thread() -> bool {
unsafe { bindings::Gecko_IsMainThread() }
}
#[allow(dead_code)]
fn is_in_servo_traversal() -> bool {
unsafe { bindings::Gecko_IsInServoTraversal() }
}
fn create_shared_context<'a>(
global_style_data: &GlobalStyleData,
guard: &'a SharedRwLockReadGuard,
per_doc_data: &'a PerDocumentStyleDataImpl,
traversal_flags: TraversalFlags,
snapshot_map: &'a ServoElementSnapshotTable,
) -> SharedStyleContext<'a> {
SharedStyleContext {
stylist: &per_doc_data.stylist,
visited_styles_enabled: per_doc_data.visited_styles_enabled(),
options: global_style_data.options.clone(),
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
guards: StylesheetGuards::same(guard),
current_time_for_animations: 0.0, // Unused for Gecko, at least for now.
traversal_flags,
snapshot_map,
}
}
fn traverse_subtree(
element: GeckoElement,
global_style_data: &GlobalStyleData,
per_doc_data: &PerDocumentStyleDataImpl,
guard: &SharedRwLockReadGuard,
traversal_flags: TraversalFlags,
snapshots: &ServoElementSnapshotTable,
) {
let shared_style_context = create_shared_context(
&global_style_data,
&guard,
&per_doc_data,
traversal_flags,
snapshots,
);
let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
servo: Merge #14436 - Make restyle tracking more granular (from bholley:granular_restyle); r=emilio The primary idea of this patch is to ditch the rigid enum of Previous/Current styles, and replace it with a series of indicators for the various types of work that needs to be performed (expanding snapshots, rematching, recascading, and damage processing). This loses us a little bit of sanity checking (since the up-to-date-ness of our style is no longer baked into the type system), but gives us a lot more flexibility that we'll need going forward (especially when we separate matching from cascading). We also eliminate get_styling_mode in favor of a method on the traversal. This patch does a few other things as ridealongs: * Temporarily eliminates the handling for transfering ownership of styles to the frame. We'll need this again at some point, but for now it's causing too much complexity for a half-implemented feature. * Ditches TRestyleDamage, which is no longer necessary post-crate-merge, and is a constant source of compilation failures from either needing to be imported or being unnecessarily imported (which varies between gecko and servo). * Expands Snapshots for the traversal root, which was missing before. * Fixes up the skip_root stuff to avoid visiting the skipped root. * Unifies parallel traversal and avoids spawning for a single work item. * Adds an explicit pre_traverse step do any pre-processing and determine whether we need to traverse at all. Source-Repo: https://github.com/servo/servo Source-Revision: b9a8ccd775c3192e3810a1730b1d0bc2b5c9dfb6
2016-12-10 04:01:05 +03:00
if !token.should_traverse() {
return;
}
debug!("Traversing subtree from {:?}", element);
let thread_pool_holder = &*STYLE_THREAD_POOL;
let pool;
let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
pool = thread_pool_holder.pool();
pool.as_ref()
} else {
None
};
let traversal = RecalcStyleOnly::new(shared_style_context);
driver::traverse_dom(&traversal, token, thread_pool);
}
/// Traverses the subtree rooted at `root` for restyling.
///
/// Returns whether the root was restyled. Whether anything else was restyled or
/// not can be inferred from the dirty bits in the rest of the tree.
#[no_mangle]
pub extern "C" fn Servo_TraverseSubtree(
root: &RawGeckoElement,
raw_data: &RawServoStyleSet,
snapshots: *const ServoElementSnapshotTable,
raw_flags: ServoTraversalFlags,
) -> bool {
let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags);
debug_assert!(!snapshots.is_null());
let element = GeckoElement(root);
debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
debug!("{:?}", ShowSubtreeData(element.as_node()));
if cfg!(debug_assertions) {
if let Some(parent) = element.traversal_parent() {
let data = parent
.borrow_data()
.expect("Styling element with unstyled parent");
assert!(
!data.styles.is_display_none(),
"Styling element with display: none parent"
);
}
}
let needs_animation_only_restyle =
element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let was_initial_style = !element.has_data();
if needs_animation_only_restyle {
debug!(
"Servo_TraverseSubtree doing animation-only restyle (aodd={})",
element.has_animation_only_dirty_descendants()
);
traverse_subtree(
element,
&global_style_data,
&per_doc_data,
&guard,
traversal_flags | TraversalFlags::AnimationOnly,
unsafe { &*snapshots },
);
}
traverse_subtree(
element,
&global_style_data,
&per_doc_data,
&guard,
traversal_flags,
unsafe { &*snapshots },
);
debug!(
"Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
element.has_dirty_descendants(),
element.has_animation_only_dirty_descendants(),
element.descendants_need_frames(),
element.needs_frame(),
element.borrow_data().unwrap()
);
if was_initial_style {
debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
false
} else {
let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
element_was_restyled
}
}
/// Checks whether the rule tree has crossed its threshold for unused nodes, and
/// if so, frees them.
#[no_mangle]
pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &RawServoStyleSet) {
let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
per_doc_data.stylist.rule_tree().maybe_gc();
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_Interpolate(
from: &RawServoAnimationValue,
to: &RawServoAnimationValue,
progress: f64,
) -> Strong<RawServoAnimationValue> {
let from_value = AnimationValue::as_arc(&from);
let to_value = AnimationValue::as_arc(&to);
if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) {
Arc::new(value).into_strong()
} else {
Strong::null()
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_IsInterpolable(
from: &RawServoAnimationValue,
to: &RawServoAnimationValue,
) -> bool {
let from_value = AnimationValue::as_arc(&from);
let to_value = AnimationValue::as_arc(&to);
from_value
.animate(to_value, Procedure::Interpolate { progress: 0.5 })
.is_ok()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_Add(
a: &RawServoAnimationValue,
b: &RawServoAnimationValue,
) -> Strong<RawServoAnimationValue> {
let a_value = AnimationValue::as_arc(&a);
let b_value = AnimationValue::as_arc(&b);
if let Ok(value) = a_value.animate(b_value, Procedure::Add) {
Arc::new(value).into_strong()
} else {
Strong::null()
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_Accumulate(
a: &RawServoAnimationValue,
b: &RawServoAnimationValue,
count: u64,
) -> Strong<RawServoAnimationValue> {
let a_value = AnimationValue::as_arc(&a);
let b_value = AnimationValue::as_arc(&b);
if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) {
Arc::new(value).into_strong()
} else {
Strong::null()
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_GetZeroValue(
value_to_match: &RawServoAnimationValue,
) -> Strong<RawServoAnimationValue> {
let value_to_match = AnimationValue::as_arc(&value_to_match);
if let Ok(zero_value) = value_to_match.to_animated_zero() {
Arc::new(zero_value).into_strong()
} else {
Strong::null()
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValues_ComputeDistance(
from: &RawServoAnimationValue,
to: &RawServoAnimationValue,
) -> f64 {
let from_value = AnimationValue::as_arc(&from);
let to_value = AnimationValue::as_arc(&to);
servo: Merge #18210 - Skip adding/accumulating ClipRect values which corresponding rect offset is auto (from mantaroh:clip-interpolation-fix); r=nox <!-- Please describe your changes on the following line: --> This is a PR for https://bugzilla.mozilla.org/show_bug.cgi?id=1390352 This patch will skip adding/accumulating the values which corresponding rect offset is auto, and make Servo_AnimationValues_ComputeDistance return negative value instead of 0.0 when the function fails to distinguish its failure. --- <!-- 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 <!-- Either: --> There are already these tests in dom/smil/tests of gecko, this PR will enable these tests. For detail, see https://bugzilla.mozilla.org/show_bug.cgi?id=1390352. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 5624c0e3f16e0057bb228627eaf9018ef88e7786 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : b387ca2a23f2e20f5344e409ec0f14f9e8457163
2017-08-31 07:21:49 +03:00
// If compute_squared_distance() failed, this function will return negative value
// in order to check whether we support the specified paced animation values.
from_value
.compute_squared_distance(to_value)
.map(|d| d.sqrt())
.unwrap_or(-1.0)
}
/// Compute one of the endpoints for the interpolation interval, compositing it with the
/// underlying value if needed.
/// An None returned value means, "Just use endpoint_value as-is."
/// It is the responsibility of the caller to ensure that |underlying_value| is provided
/// when it will be used.
fn composite_endpoint(
endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
composite: CompositeOperation,
underlying_value: Option<&AnimationValue>,
) -> Option<AnimationValue> {
match endpoint_value {
Some(endpoint_value) => match composite {
CompositeOperation::Add => underlying_value
.expect("We should have an underlying_value")
.animate(endpoint_value, Procedure::Add)
.ok(),
CompositeOperation::Accumulate => underlying_value
.expect("We should have an underlying value")
.animate(endpoint_value, Procedure::Accumulate { count: 1 })
.ok(),
_ => None,
},
None => underlying_value.map(|v| v.clone()),
}
}
/// Accumulate one of the endpoints of the animation interval.
/// A returned value of None means, "Just use endpoint_value as-is."
fn accumulate_endpoint(
endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
composited_value: Option<AnimationValue>,
last_value: &AnimationValue,
current_iteration: u64,
) -> Option<AnimationValue> {
debug_assert!(
endpoint_value.is_some() || composited_value.is_some(),
"Should have a suitable value to use"
);
let count = current_iteration;
match composited_value {
Some(endpoint) => last_value
.animate(&endpoint, Procedure::Accumulate { count })
.ok()
.or(Some(endpoint)),
None => last_value
.animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
.ok(),
}
}
/// Compose the animation segment. We composite it with the underlying_value and last_value if
/// needed.
/// The caller is responsible for providing an underlying value and last value
/// in all situations where there are needed.
fn compose_animation_segment(
segment: &structs::AnimationPropertySegment,
underlying_value: Option<&AnimationValue>,
last_value: Option<&AnimationValue>,
iteration_composite: IterationCompositeOperation,
current_iteration: u64,
total_progress: f64,
segment_progress: f64,
) -> AnimationValue {
// Extract keyframe values.
let raw_from_value;
let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() {
raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr };
Some(AnimationValue::as_arc(&raw_from_value))
} else {
None
};
let raw_to_value;
let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() {
raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr };
Some(AnimationValue::as_arc(&raw_to_value))
} else {
None
};
let mut composited_from_value = composite_endpoint(
keyframe_from_value,
segment.mFromComposite,
underlying_value,
);
let mut composited_to_value =
composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
debug_assert!(
keyframe_from_value.is_some() || composited_from_value.is_some(),
"Should have a suitable from value to use"
);
debug_assert!(
keyframe_to_value.is_some() || composited_to_value.is_some(),
"Should have a suitable to value to use"
);
// Apply iteration composite behavior.
if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
let last_value = last_value
.unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
composited_from_value = accumulate_endpoint(
keyframe_from_value,
composited_from_value,
last_value,
current_iteration,
);
composited_to_value = accumulate_endpoint(
keyframe_to_value,
composited_to_value,
last_value,
current_iteration,
);
}
// Use the composited value if there is one, otherwise, use the original keyframe value.
let from = composited_from_value
.as_ref()
.unwrap_or_else(|| keyframe_from_value.unwrap());
let to = composited_to_value
.as_ref()
.unwrap_or_else(|| keyframe_to_value.unwrap());
if segment.mToKey == segment.mFromKey {
return if total_progress < 0. {
from.clone()
} else {
to.clone()
};
}
match from.animate(
to,
Procedure::Interpolate {
progress: segment_progress,
},
) {
Ok(value) => value,
_ => {
if segment_progress < 0.5 {
from.clone()
} else {
to.clone()
}
},
}
}
#[no_mangle]
pub extern "C" fn Servo_ComposeAnimationSegment(
segment: &structs::AnimationPropertySegment,
underlying_value: Option<&RawServoAnimationValue>,
last_value: Option<&RawServoAnimationValue>,
iteration_composite: IterationCompositeOperation,
progress: f64,
current_iteration: u64,
) -> Strong<RawServoAnimationValue> {
let underlying_value = AnimationValue::arc_from_borrowed(&underlying_value).map(|v| &**v);
let last_value = AnimationValue::arc_from_borrowed(&last_value).map(|v| &**v);
let result = compose_animation_segment(
segment,
underlying_value,
last_value,
iteration_composite,
current_iteration,
progress,
progress,
);
Arc::new(result).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationCompose(
raw_value_map: &mut structs::RawServoAnimationValueMap,
base_values: &structs::RawServoAnimationValueTable,
css_property: nsCSSPropertyID,
segment: &structs::AnimationPropertySegment,
last_segment: &structs::AnimationPropertySegment,
computed_timing: &structs::ComputedTiming,
iteration_composite: IterationCompositeOperation,
) {
use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
let property = match LonghandId::from_nscsspropertyid(css_property) {
Ok(longhand) if longhand.is_animatable() => longhand,
_ => return,
};
let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
// We will need an underlying value if either of the endpoints is null...
let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
segment.mToValue.mServo.mRawPtr.is_null() ||
// ... or if they have a non-replace composite mode ...
segment.mFromComposite != CompositeOperation::Replace ||
segment.mToComposite != CompositeOperation::Replace ||
// ... or if we accumulate onto the last value and it is null.
(iteration_composite == IterationCompositeOperation::Accumulate &&
computed_timing.mCurrentIteration > 0 &&
last_segment.mToValue.mServo.mRawPtr.is_null());
// If either of the segment endpoints are null, get the underlying value to
// use from the current value in the values map (set by a lower-priority
// effect), or, if there is no current value, look up the cached base value
// for this property.
let underlying_value = if need_underlying_value {
let previous_composed_value = value_map.get(&property).cloned();
previous_composed_value.or_else(|| {
let raw_base_style =
unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() };
AnimationValue::arc_from_borrowed(&raw_base_style)
.map(|v| &**v)
.cloned()
})
} else {
None
};
if need_underlying_value && underlying_value.is_none() {
warn!("Underlying value should be valid when we expect to use it");
return;
}
let raw_last_value;
let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() {
raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr };
Some(&**AnimationValue::as_arc(&raw_last_value))
} else {
None
};
let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
let position = if segment.mToKey == segment.mFromKey {
// Note: compose_animation_segment doesn't use this value
// if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
progress
} else {
unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
};
let result = compose_animation_segment(
segment,
underlying_value.as_ref(),
last_value,
iteration_composite,
computed_timing.mCurrentIteration,
progress,
position,
);
value_map.insert(property, result);
}
macro_rules! get_property_id_from_nscsspropertyid {
($property_id: ident, $ret: expr) => {{
match PropertyId::from_nscsspropertyid($property_id) {
Ok(property_id) => property_id,
Err(()) => {
return $ret;
},
}
}};
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Serialize(
value: &RawServoAnimationValue,
property: nsCSSPropertyID,
raw_data: &RawServoStyleSet,
buffer: &mut nsAString,
) {
let uncomputed_value = AnimationValue::as_arc(&value).uncompute();
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
.single_value_to_css(
&get_property_id_from_nscsspropertyid!(property, ()),
buffer,
None,
None, /* No extra custom properties */
&data.stylist.device(),
);
debug_assert!(rv.is_ok());
}
/// Debug: MOZ_DBG for AnimationValue.
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Dump(
value: &RawServoAnimationValue,
result: &mut nsAString,
) {
let value = AnimationValue::as_arc(&value);
write!(result, "{:?}", value).unwrap();
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetColor(
value: &RawServoAnimationValue,
foreground_color: structs::nscolor,
) -> structs::nscolor {
use style::gecko::values::convert_nscolor_to_rgba;
use style::gecko::values::convert_rgba_to_nscolor;
use style::values::animated::ToAnimatedValue;
use style::values::computed::color::Color as ComputedColor;
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::BackgroundColor(color) => {
let computed: ComputedColor = ToAnimatedValue::from_animated_value(color);
let foreground_color = convert_nscolor_to_rgba(foreground_color);
convert_rgba_to_nscolor(&computed.to_rgba(foreground_color))
},
_ => panic!("Other color properties are not supported yet"),
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_IsCurrentColor(value: &RawServoAnimationValue) -> bool {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::BackgroundColor(color) => color.is_currentcolor(),
_ => {
debug_assert!(false, "Other color properties are not supported yet");
false
},
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &RawServoAnimationValue) -> f32 {
let value = AnimationValue::as_arc(&value);
if let AnimationValue::Opacity(opacity) = **value {
opacity
} else {
panic!("The AnimationValue should be Opacity");
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Opacity(opacity)).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Color(
color_property: nsCSSPropertyID,
color: structs::nscolor,
) -> Strong<RawServoAnimationValue> {
use style::gecko::values::convert_nscolor_to_rgba;
use style::values::animated::color::RGBA as AnimatedRGBA;
let property = LonghandId::from_nscsspropertyid(color_property)
.expect("We don't have shorthand property animation value");
let rgba = convert_nscolor_to_rgba(color);
let animatedRGBA = AnimatedRGBA::new(
rgba.red_f32(),
rgba.green_f32(),
rgba.blue_f32(),
rgba.alpha_f32(),
);
match property {
LonghandId::BackgroundColor => {
Arc::new(AnimationValue::BackgroundColor(animatedRGBA.into())).into_strong()
},
_ => panic!("Should be background-color property"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
value: &RawServoAnimationValue,
) -> *const computed::Scale {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Scale(ref value) => value,
_ => unreachable!("Expected scale"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
value: &RawServoAnimationValue,
) -> *const computed::Translate {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Translate(ref value) => value,
_ => unreachable!("Expected translate"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
value: &RawServoAnimationValue,
) -> *const computed::Rotate {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Rotate(ref value) => value,
_ => unreachable!("Expected rotate"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
value: &RawServoAnimationValue,
) -> *const computed::Transform {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Transform(ref value) => value,
_ => unreachable!("Unsupported transform animation value"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
value: &RawServoAnimationValue,
) -> *const computed::motion::OffsetPath {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::OffsetPath(ref value) => value,
_ => unreachable!("Expected offset-path"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
value: &RawServoAnimationValue,
) -> *const computed::LengthPercentage {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::OffsetDistance(ref value) => value,
_ => unreachable!("Expected offset-distance"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
value: &RawServoAnimationValue,
) -> *const computed::motion::OffsetRotate {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::OffsetRotate(ref value) => value,
_ => unreachable!("Expected offset-rotate"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
value: &RawServoAnimationValue,
) -> *const computed::position::PositionOrAuto {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::OffsetAnchor(ref value) => value,
_ => unreachable!("Expected offset-anchor"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
r: &computed::Rotate,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Rotate(r.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Translate(
t: &computed::Translate,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Translate(t.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Scale(
s: &computed::Scale,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Scale(s.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Transform(
transform: &computed::Transform,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Transform(transform.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
p: &computed::motion::OffsetPath,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::OffsetPath(p.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
d: &computed::length::LengthPercentage,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::OffsetDistance(d.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
r: &computed::motion::OffsetRotate,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::OffsetRotate(*r)).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
p: &computed::position::PositionOrAuto,
) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::OffsetAnchor(p.clone())).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_DeepEqual(
this: &RawServoAnimationValue,
other: &RawServoAnimationValue,
) -> bool {
let this_value = AnimationValue::as_arc(&this);
let other_value = AnimationValue::as_arc(&other);
this_value == other_value
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Uncompute(
value: &RawServoAnimationValue,
) -> Strong<RawServoDeclarationBlock> {
let value = AnimationValue::as_arc(&value);
let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(
global_style_data
.shared_lock
.wrap(PropertyDeclarationBlock::with_one(
value.uncompute(),
Importance::Normal,
)),
)
.into_strong()
}
#[inline]
fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
let w = ByteBuf {
mData: v.as_mut_ptr(),
mLen: v.len(),
mCapacity: v.capacity(),
};
std::mem::forget(v);
w
}
#[inline]
fn view_byte_buf(b: &ByteBuf) -> &[u8] {
if b.mData.is_null() {
debug_assert_eq!(b.mCapacity, 0);
return &[];
}
unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
}
macro_rules! impl_basic_serde_funcs {
($ser_name:ident, $de_name:ident, $computed_type:ty) => {
#[no_mangle]
pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
let buf = match serialize(v) {
Ok(buf) => buf,
Err(..) => return false,
};
*output = create_byte_buf_from_vec(buf);
true
}
#[no_mangle]
pub extern "C" fn $de_name(input: &ByteBuf, v: &mut $computed_type) -> bool {
let buf = match deserialize(view_byte_buf(input)) {
Ok(buf) => buf,
Err(..) => return false,
};
*v = buf;
true
}
};
}
impl_basic_serde_funcs!(
Servo_LengthPercentage_Serialize,
Servo_LengthPercentage_Deserialize,
computed::LengthPercentage
);
impl_basic_serde_funcs!(
Servo_StyleRotate_Serialize,
Servo_StyleRotate_Deserialize,
computed::transform::Rotate
);
impl_basic_serde_funcs!(
Servo_StyleScale_Serialize,
Servo_StyleScale_Deserialize,
computed::transform::Scale
);
impl_basic_serde_funcs!(
Servo_StyleTranslate_Serialize,
Servo_StyleTranslate_Deserialize,
computed::transform::Translate
);
impl_basic_serde_funcs!(
Servo_StyleTransform_Serialize,
Servo_StyleTransform_Deserialize,
computed::transform::Transform
);
impl_basic_serde_funcs!(
Servo_StyleOffsetPath_Serialize,
Servo_StyleOffsetPath_Deserialize,
computed::motion::OffsetPath
);
impl_basic_serde_funcs!(
Servo_StyleOffsetRotate_Serialize,
Servo_StyleOffsetRotate_Deserialize,
computed::motion::OffsetRotate
);
impl_basic_serde_funcs!(
Servo_StylePositionOrAuto_Serialize,
Servo_StylePositionOrAuto_Deserialize,
computed::position::PositionOrAuto
);
#[no_mangle]
pub extern "C" fn Servo_SVGPathData_Normalize(
input: &specified::SVGPathData,
output: &mut specified::SVGPathData,
) {
*output = input.normalize();
}
// Return the ComputedValues by a base ComputedValues and the rules.
fn resolve_rules_for_element_with_context<'a>(
element: GeckoElement<'a>,
mut context: StyleContext<GeckoElement<'a>>,
rules: StrongRuleNode,
) -> Arc<ComputedValues> {
use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
// This currently ignores visited styles, which seems acceptable, as
// existing browsers don't appear to animate visited styles.
let inputs = CascadeInputs {
rules: Some(rules),
visited_rules: None,
};
// Actually `PseudoElementResolution` doesn't matter.
let mut resolver = StyleResolverForElement::new(
element,
&mut context,
RuleInclusion::All,
PseudoElementResolution::IfApplicable,
);
resolver
.cascade_style_and_visited_with_default_parents(inputs)
.0
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap> {
Box::<AnimationValueMap>::default().into_ffi()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(
value_map: *mut structs::RawServoAnimationValueMap,
) {
AnimationValueMap::drop_ffi(value_map)
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValueMap_GetValue(
raw_value_map: &mut structs::RawServoAnimationValueMap,
property_id: nsCSSPropertyID,
) -> Strong<RawServoAnimationValue> {
let property = match LonghandId::from_nscsspropertyid(property_id) {
Ok(longhand) => longhand,
Err(()) => return Strong::null(),
};
let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
value_map.get(&property).map_or(Strong::null(), |value| {
Arc::new(value.clone()).into_strong()
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
raw_style_set: &RawServoStyleSet,
element: &RawGeckoElement,
computed_values: &ComputedValues,
snapshots: *const ServoElementSnapshotTable,
) -> Strong<ComputedValues> {
debug_assert!(!snapshots.is_null());
let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
let rules = match computed_values.rules {
None => return computed_values.clone_arc().into(),
Some(ref rules) => rules,
};
let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
if without_animations_rules == *rules {
return computed_values.clone_arc().into();
}
let element = GeckoElement(element);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let shared = create_shared_context(
&global_style_data,
&guard,
&doc_data,
TraversalFlags::empty(),
unsafe { &*snapshots },
);
let mut tlc = ThreadLocalStyleContext::new(&shared);
let context = StyleContext {
shared: &shared,
thread_local: &mut tlc,
};
resolve_rules_for_element_with_context(element, context, without_animations_rules).into()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_GetComputedValuesByAddingAnimation(
raw_style_set: &RawServoStyleSet,
element: &RawGeckoElement,
computed_values: &ComputedValues,
snapshots: *const ServoElementSnapshotTable,
animation_value: &RawServoAnimationValue,
) -> Strong<ComputedValues> {
debug_assert!(!snapshots.is_null());
let rules = match computed_values.rules {
None => return Strong::null(),
Some(ref rules) => rules,
};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let uncomputed_value = AnimationValue::as_arc(&animation_value).uncompute();
let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
let with_animations_rules = {
let guards = StylesheetGuards::same(&guard);
let declarations = Arc::new(global_style_data.shared_lock.wrap(
PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal),
));
doc_data
.stylist
.rule_tree()
.add_animation_rules_at_transition_level(rules, declarations, &guards)
};
let element = GeckoElement(element);
if element.borrow_data().is_none() {
return Strong::null();
}
let shared = create_shared_context(
&global_style_data,
&guard,
&doc_data,
TraversalFlags::empty(),
unsafe { &*snapshots },
);
let mut tlc: ThreadLocalStyleContext<GeckoElement> = ThreadLocalStyleContext::new(&shared);
let context = StyleContext {
shared: &shared,
thread_local: &mut tlc,
};
resolve_rules_for_element_with_context(element, context, with_animations_rules).into()
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
computed_values: &ComputedValues,
property_id: nsCSSPropertyID,
) -> Strong<RawServoAnimationValue> {
let property = match LonghandId::from_nscsspropertyid(property_id) {
Ok(longhand) => longhand,
Err(()) => return Strong::null(),
};
match AnimationValue::from_computed_values(property, &computed_values) {
Some(v) => Arc::new(v).into_strong(),
None => Strong::null(),
}
}
#[no_mangle]
pub extern "C" fn Servo_ResolveLogicalProperty(
property_id: nsCSSPropertyID,
style: &ComputedValues,
) -> nsCSSPropertyID {
let longhand = LonghandId::from_nscsspropertyid(property_id)
.expect("We shouldn't need to care about shorthands");
longhand
.to_physical(style.writing_mode)
.to_nscsspropertyid()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
prop: &nsACString,
) -> nsCSSPropertyID {
match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_GetName(
prop: nsCSSPropertyID,
out_length: *mut u32,
) -> *const u8 {
let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
Ok(p) => {
let name = p.name();
(name.as_bytes().as_ptr(), name.len())
},
Err(..) => (ptr::null(), 0),
};
*out_length = len as u32;
ptr
}
macro_rules! parse_enabled_property_name {
($prop_name:ident, $found:ident, $default:expr) => {{
let prop_name = $prop_name.as_str_unchecked();
match PropertyId::parse_enabled_for_all_content(prop_name) {
Ok(p) => {
*$found = true;
p
},
Err(..) => {
*$found = false;
return $default;
},
}
}};
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_IsShorthand(
prop_name: &nsACString,
found: *mut bool,
) -> bool {
let prop_id = parse_enabled_property_name!(prop_name, found, false);
prop_id.is_shorthand()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_IsInherited(prop_name: &nsACString) -> bool {
let prop_name = prop_name.as_str_unchecked();
let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
Ok(id) => id,
Err(_) => return false,
};
let longhand_id = match prop_id {
PropertyId::Custom(_) => return true,
PropertyId::Longhand(id) | PropertyId::LonghandAlias(id, _) => id,
PropertyId::Shorthand(id) | PropertyId::ShorthandAlias(id, _) => {
id.longhands().next().unwrap()
},
};
longhand_id.inherited()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_SupportsType(
prop_name: &nsACString,
ty: u8,
found: *mut bool,
) -> bool {
let prop_id = parse_enabled_property_name!(prop_name, found, false);
prop_id.supports_type(ty)
}
// TODO(emilio): We could use ThinVec instead of nsTArray.
#[no_mangle]
pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
prop_name: &nsACString,
found: *mut bool,
result: &mut nsTArray<nsString>,
) {
let prop_id = parse_enabled_property_name!(prop_name, found, ());
// Use B-tree set for unique and sorted result.
let mut values = BTreeSet::<&'static str>::new();
prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
let mut extras = vec![];
if values.contains("transparent") {
// This is a special value devtools use to avoid inserting the
// long list of color keywords. We need to prepend it to values.
extras.push("COLOR");
}
let len = extras.len() + values.len();
bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
dest.write_str(src).unwrap();
}
}
#[no_mangle]
pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
NonCustomPropertyId::from_nscsspropertyid(prop)
.ok()
.map_or(false, |p| p.is_animatable())
}
#[no_mangle]
pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
NonCustomPropertyId::from_nscsspropertyid(prop)
.ok()
.map_or(false, |p| p.is_transitionable())
}
#[no_mangle]
pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
match LonghandId::from_nscsspropertyid(property) {
Ok(longhand) => longhand.is_discrete_animatable(),
Err(()) => return false,
}
}
#[no_mangle]
pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
unsafe { GeckoElement(element).clear_data() };
}
servo: Merge #17953 - stylo: Measure Elements and ComputedValues (from nnethercote:bug-1383977); r=Manishearth This is for https://bugzilla.mozilla.org/show_bug.cgi?id=1383977. <!-- Please describe your changes on the following line: --> The patch provides FFI access to Gecko's SeenPtrs type from Rust, in order to record what has already been measured when measuring Arcs. (The SeenPtrs must be initialized on the Gecko side because the same table is reused for measuring all Elements within a window, because Elements can share ComputedValues.) I have confirmed with DMD that this is working correctly. The patch also introduces MallocSizeOfRepeats, which is like MallocSizeOf but takes a SizeOfState, which holds a SeenPtrs table. --- <!-- 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 #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because testing is done on mozilla-central CI. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 32e2e546ac452cf83a0fb7e1d4521df23ec5eeda --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 99f0e9952564cf20c7a2a1594d86f29c55062492
2017-08-03 03:39:15 +03:00
#[no_mangle]
pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
seen_ptrs: *mut SeenPtrs,
element: &RawGeckoElement,
) -> usize {
servo: Merge #17953 - stylo: Measure Elements and ComputedValues (from nnethercote:bug-1383977); r=Manishearth This is for https://bugzilla.mozilla.org/show_bug.cgi?id=1383977. <!-- Please describe your changes on the following line: --> The patch provides FFI access to Gecko's SeenPtrs type from Rust, in order to record what has already been measured when measuring Arcs. (The SeenPtrs must be initialized on the Gecko side because the same table is reused for measuring all Elements within a window, because Elements can share ComputedValues.) I have confirmed with DMD that this is working correctly. The patch also introduces MallocSizeOfRepeats, which is like MallocSizeOf but takes a SizeOfState, which holds a SeenPtrs table. --- <!-- 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 #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because testing is done on mozilla-central CI. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 32e2e546ac452cf83a0fb7e1d4521df23ec5eeda --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 99f0e9952564cf20c7a2a1594d86f29c55062492
2017-08-03 03:39:15 +03:00
let element = GeckoElement(element);
let borrow = element.borrow_data();
if let Some(data) = borrow {
let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
Some(Box::new(have_seen_ptr)),
);
servo: Merge #18452 - Overhaul MallocSizeOf and related things (from nnethercote:bug-1398737); r=jdm This patch makes the MallocSizeOf stuff in Stylo work more like the HeapSizeOf stuff already in Servo, except better. In particular, it adds deriving support for MallocSizeOf, which will make it easier to improve coverage. The patch does the following. - Combines servo/components/style/stylesheets/memory.rs and the heapsize crate into a new crate, malloc_size_of. - Forks the heapsize_derive crate, calling it malloc_size_of, so that MallocSizeOf can be derived. - Both the new crates have MIT/Apache licenses, like heapsize, in case they are incorporated into heapsize in the future. - Renames the methods within MallocSizeOf and the related traits so they are more concise. - Removes MallocSizeOfWithGuard. - Adds `derive(MallocSizeOf)` to a lot of types, in some cases replacing an equivalent or almost-equivalent hand-written implementation. - Adds stuff so that Rc/Arc can be handled properly. <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because tested on Gecko side. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 7f4cb1861b172423781a369b2decca6c65d60546 --HG-- rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of/LICENSE-MIT rename : servo/components/jstraceable_derive/Cargo.toml => servo/components/malloc_size_of_derive/Cargo.toml rename : servo/components/hashglobe/LICENSE-APACHE => servo/components/malloc_size_of_derive/LICENSE-APACHE rename : servo/components/hashglobe/LICENSE-MIT => servo/components/malloc_size_of_derive/LICENSE-MIT extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : a8254c4ae15901b764d918355e900a1e74d6eb03
2017-09-12 06:11:25 +03:00
(*data).size_of_excluding_cvs(&mut ops)
servo: Merge #17953 - stylo: Measure Elements and ComputedValues (from nnethercote:bug-1383977); r=Manishearth This is for https://bugzilla.mozilla.org/show_bug.cgi?id=1383977. <!-- Please describe your changes on the following line: --> The patch provides FFI access to Gecko's SeenPtrs type from Rust, in order to record what has already been measured when measuring Arcs. (The SeenPtrs must be initialized on the Gecko side because the same table is reused for measuring all Elements within a window, because Elements can share ComputedValues.) I have confirmed with DMD that this is working correctly. The patch also introduces MallocSizeOfRepeats, which is like MallocSizeOf but takes a SizeOfState, which holds a SeenPtrs table. --- <!-- 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 #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because testing is done on mozilla-central CI. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 32e2e546ac452cf83a0fb7e1d4521df23ec5eeda --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 99f0e9952564cf20c7a2a1594d86f29c55062492
2017-08-03 03:39:15 +03:00
} else {
0
}
}
#[no_mangle]
pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
element: &RawGeckoElement,
) -> *const ComputedValues {
let element = GeckoElement(element);
let data = match element.borrow_data() {
Some(d) => d,
None => return ptr::null(),
};
&**data.styles.primary() as *const _
}
#[no_mangle]
pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
element: &RawGeckoElement,
index: usize,
) -> *const ComputedValues {
let element = GeckoElement(element);
let data = match element.borrow_data() {
Some(d) => d,
None => return ptr::null(),
};
match data.styles.pseudos.as_array()[index].as_ref() {
Some(style) => &**style as *const _,
None => ptr::null(),
}
}
#[no_mangle]
pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
let element = GeckoElement(element);
let data = element
.get_data()
.expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
// This function is hot, so we bypass the AtomicRefCell.
//
// It would be nice to also assert that we're not in the servo traversal,
// but this function is called at various intermediate checkpoints when
// managing the traversal on the Gecko side.
debug_assert!(is_main_thread());
unsafe { &*data.as_ptr() }.styles.is_display_none()
}
#[no_mangle]
pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
let element = GeckoElement(element);
let data = element
.get_data()
.expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
debug_assert!(is_main_thread());
unsafe { &*data.as_ptr() }
.styles
.primary()
.get_box()
.clone_display()
.is_contents()
}
#[no_mangle]
pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
let element = GeckoElement(element);
let data = element
.borrow_data()
.expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
data.flags
.contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
}
fn mode_to_origin(mode: SheetParsingMode) -> Origin {
match mode {
SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
SheetParsingMode::eUserSheetFeatures => Origin::User,
SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_Empty(
mode: SheetParsingMode,
) -> Strong<RawServoStyleSheetContents> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let origin = mode_to_origin(mode);
let shared_lock = &global_style_data.shared_lock;
Arc::new(StylesheetContents::from_str(
"",
unsafe { dummy_url_data() }.clone(),
origin,
shared_lock,
/* loader = */ None,
None,
QuirksMode::NoQuirks,
0,
/* use_counters = */ None,
AllowImportRules::Yes,
/* sanitization_data = */ None,
))
.into_strong()
}
/// Note: The load_data corresponds to this sheet, and is passed as the parent
/// load data for child sheet loads. It may be null for certain cases where we
/// know we won't have child loads.
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
loader: *mut Loader,
stylesheet: *mut DomStyleSheet,
load_data: *mut SheetLoadData,
bytes: &nsACString,
mode: SheetParsingMode,
extra_data: *mut URLExtraData,
line_number_offset: u32,
quirks_mode: nsCompatibility,
reusable_sheets: *mut LoaderReusableStyleSheets,
use_counters: Option<&UseCounters>,
allow_import_rules: AllowImportRules,
sanitization_kind: SanitizationKind,
sanitized_output: Option<&mut nsAString>,
) -> Strong<RawServoStyleSheetContents> {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let input = bytes.as_str_unchecked();
let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
let url_data = UrlExtraData::from_ptr_ref(&extra_data);
let loader = if loader.is_null() {
None
} else {
debug_assert!(
sanitized_output.is_none(),
"Shouldn't trigger @import loads for sanitization",
);
Some(StylesheetLoader::new(
loader,
stylesheet,
load_data,
reusable_sheets,
))
};
// FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
let loader: Option<&dyn StyleStylesheetLoader> = match loader {
None => None,
Some(ref s) => Some(s),
};
let mut sanitization_data = SanitizationData::new(sanitization_kind);
let contents = Arc::new(StylesheetContents::from_str(
input,
url_data.clone(),
mode_to_origin(mode),
&global_style_data.shared_lock,
loader,
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
quirks_mode.into(),
line_number_offset,
use_counters,
allow_import_rules,
sanitization_data.as_mut(),
));
if let Some(data) = sanitization_data {
sanitized_output
.unwrap()
.assign_utf8(data.take().as_bytes());
}
contents.into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
load_data: *mut SheetLoadDataHolder,
extra_data: *mut URLExtraData,
bytes: &nsACString,
mode: SheetParsingMode,
line_number_offset: u32,
quirks_mode: nsCompatibility,
should_record_use_counters: bool,
allow_import_rules: AllowImportRules,
) {
let load_data = RefPtr::new(load_data);
let extra_data = UrlExtraData::new(extra_data);
let mut sheet_bytes = nsCString::new();
sheet_bytes.assign(bytes);
let async_parser = AsyncStylesheetParser::new(
load_data,
extra_data,
sheet_bytes,
mode_to_origin(mode),
quirks_mode.into(),
line_number_offset,
should_record_use_counters,
allow_import_rules,
);
if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
thread_pool.spawn(|| {
profiler_label!(Parse);
async_parser.parse();
});
} else {
async_parser.parse();
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
debug_assert!(is_main_thread() && !is_in_servo_traversal());
StyleThreadPool::shutdown();
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
extra_data: *mut URLExtraData,
shared_rules: &ServoCssRules,
) -> Strong<RawServoStyleSheetContents> {
let shared_rules = Locked::<CssRules>::as_arc(&shared_rules);
Arc::new(StylesheetContents::from_shared_data(
shared_rules.clone_arc(),
Origin::UserAgent,
UrlExtraData::new(extra_data),
QuirksMode::NoQuirks,
))
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
raw_data: &RawServoStyleSet,
sheet: *const DomStyleSheet,
) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let data = &mut *data;
let guard = global_style_data.shared_lock.read();
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
data.stylist.append_stylesheet(sheet, &guard);
}
#[no_mangle]
pub extern "C" fn Servo_AuthorStyles_Create() -> Owned<RawServoAuthorStyles> {
Box::new(AuthorStyles::<GeckoStyleSheet>::new()).into_ffi()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut RawServoAuthorStyles) {
AuthorStyles::drop_ffi(styles)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
styles: &mut RawServoAuthorStyles,
sheet: *const DomStyleSheet,
) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let sheet = GeckoStyleSheet::new(sheet);
styles.stylesheets.append_stylesheet(None, sheet, &guard);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
styles: &mut RawServoAuthorStyles,
sheet: *const DomStyleSheet,
before_sheet: *const DomStyleSheet,
) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
styles.stylesheets.insert_stylesheet_before(
None,
GeckoStyleSheet::new(sheet),
GeckoStyleSheet::new(before_sheet),
&guard,
);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
styles: &mut RawServoAuthorStyles,
sheet: *const DomStyleSheet,
) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
styles
.stylesheets
.remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut RawServoAuthorStyles) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
styles.stylesheets.force_dirty();
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_IsDirty(styles: &RawServoAuthorStyles) -> bool {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
styles.stylesheets.dirty()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_Flush(
styles: &mut RawServoAuthorStyles,
document_set: &RawServoStyleSet,
) {
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
// Try to avoid the atomic borrow below if possible.
if !styles.stylesheets.dirty() {
return;
}
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let document_data = PerDocumentStyleData::from_ffi(document_set).borrow();
let stylist = &document_data.stylist;
// TODO(emilio): This is going to need an element or something to do proper
// invalidation in Shadow roots.
styles.flush::<GeckoElement>(stylist.device(), stylist.quirks_mode(), &guard);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
declarations: &RawServoDeclarationBlock,
) -> usize {
use malloc_size_of::MallocSizeOf;
use malloc_size_of::MallocUnconditionalShallowSizeOf;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
None,
);
Locked::<PropertyDeclarationBlock>::as_arc(&declarations).with_arc(|declarations| {
let mut n = 0;
n += declarations.unconditional_shallow_size_of(&mut ops);
n += declarations.read_with(&guard).size_of(&mut ops);
n
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
styles: &RawServoAuthorStyles,
) -> usize {
// We cannot `use` MallocSizeOf at the top level, otherwise the compiler
// would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
// there.
use malloc_size_of::MallocSizeOf;
let malloc_size_of = malloc_size_of.unwrap();
let malloc_size_of_this =
malloc_size_of(styles as *const RawServoAuthorStyles as *const c_void);
let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
let mut ops = MallocSizeOfOps::new(
malloc_size_of,
Some(malloc_enclosing_size_of.unwrap()),
None,
);
malloc_size_of_this + styles.size_of(&mut ops)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
document_set: &RawServoStyleSet,
non_document_styles: &mut nsTArray<&mut RawServoAuthorStyles>,
may_affect_default_style: bool,
) -> structs::MediumFeaturesChangedResult {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
// NOTE(emilio): We don't actually need to flush the stylist here and ensure
// it's up to date.
//
// In case it isn't we would trigger a rebuild + restyle as needed too.
//
// We need to ensure the default computed values are up to date though,
// because those can influence the result of media query evaluation.
let mut document_data = PerDocumentStyleData::from_ffi(document_set).borrow_mut();
if may_affect_default_style {
document_data.stylist.device_mut().reset_computed_values();
}
let guards = StylesheetGuards::same(&guard);
let origins_in_which_rules_changed = document_data
.stylist
.media_features_change_changed_style(&guards, document_data.stylist.device());
let affects_document_rules = !origins_in_which_rules_changed.is_empty();
if affects_document_rules {
document_data
.stylist
.force_stylesheet_origins_dirty(origins_in_which_rules_changed);
}
let mut affects_non_document_rules = false;
for author_styles in &mut **non_document_styles {
let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(&mut *author_styles);
let affected_style = author_styles.stylesheets.iter().any(|sheet| {
!author_styles.data.media_feature_affected_matches(
sheet,
&guards.author,
document_data.stylist.device(),
document_data.stylist.quirks_mode(),
)
});
if affected_style {
affects_non_document_rules = true;
author_styles.stylesheets.force_dirty();
}
}
let uses_viewport_units = document_data.stylist.device().used_viewport_size();
structs::MediumFeaturesChangedResult {
mAffectsDocumentRules: affects_document_rules,
mAffectsNonDocumentRules: affects_non_document_rules,
mUsesViewportUnits: uses_viewport_units,
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
raw_data: &RawServoStyleSet,
sheet: *const DomStyleSheet,
before_sheet: *const DomStyleSheet,
) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let data = &mut *data;
let guard = global_style_data.shared_lock.read();
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
data.stylist.insert_stylesheet_before(
sheet,
unsafe { GeckoStyleSheet::new(before_sheet) },
&guard,
);
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
raw_data: &RawServoStyleSet,
sheet: *const DomStyleSheet,
) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let data = &mut *data;
let guard = global_style_data.shared_lock.read();
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
data.stylist.remove_stylesheet(sheet, &guard);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
raw_data: &RawServoStyleSet,
origin: Origin,
index: usize,
) -> *const DomStyleSheet {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
data.stylist
.sheet_at(origin, index)
.map_or(ptr::null(), |s| s.raw())
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
raw_data: &RawServoStyleSet,
origin: Origin,
) -> usize {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
data.stylist.sheet_count(origin)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
raw_data: &RawServoStyleSet,
doc_element: Option<&RawGeckoElement>,
snapshots: *const ServoElementSnapshotTable,
) {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let doc_element = doc_element.map(GeckoElement);
let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
if have_invalidations && doc_element.is_some() {
// The invalidation machinery propagates the bits up, but we still need
// to tell the Gecko restyle root machinery about it.
bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
raw_data: &RawServoStyleSet,
changed_origins: OriginFlags,
) {
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.stylist
.force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
raw_data: &RawServoStyleSet,
author_style_disabled: bool,
) {
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let enabled = if author_style_disabled {
AuthorStylesEnabled::No
} else {
AuthorStylesEnabled::Yes
};
data.stylist.set_author_styles_enabled(enabled);
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &RawServoStyleSheetContents) -> bool {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
!StylesheetContents::as_arc(&raw_contents)
.rules
.read_with(&guard)
.0
.is_empty()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_GetRules(
sheet: &RawServoStyleSheetContents,
) -> Strong<ServoCssRules> {
StylesheetContents::as_arc(&sheet)
.rules
.clone()
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_Clone(
raw_sheet: &RawServoStyleSheetContents,
reference_sheet: *const DomStyleSheet,
) -> Strong<RawServoStyleSheetContents> {
use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let contents = StylesheetContents::as_arc(&raw_sheet);
let params = DeepCloneParams { reference_sheet };
Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, &params))
.into_strong()
}
servo: Merge #17044 - Introduce and start using the MallocSizeOf trait (from nnethercote:MallocSizeOf); r=emilio MallocSizeOf is similar to the existing HeapSizeOf trait from the heapsize crate. The only difference is that MallocSizeOf's malloc_size_of_children() function takes an additional MallocSizeOfFn argument, which is used to measure heap blocks. This extra argument makes MallocSizeOf match how Gecko's memory measurements work, and is required for Stylo to integrate with DMD. The patch also introduces a second trait, MallocSizeOfWithGuard, which is much the same as MallocSizeOf, but with a |guard| argument for the global style lock. Finally, the patch uses the new traits to measure a small amount of Stylo's memory usage. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because code is only for Gecko integration. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: aca09436b71e6defe007e1d17a9d79214d094a7b --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 1d5dc4e7ab75e8e0332922396b5b55ed67c4572e
2017-05-29 05:10:25 +03:00
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
malloc_size_of: GeckoMallocSizeOf,
2017-09-18 07:19:54 +03:00
malloc_enclosing_size_of: GeckoMallocSizeOf,
sheet: &RawServoStyleSheetContents,
) -> usize {
servo: Merge #17044 - Introduce and start using the MallocSizeOf trait (from nnethercote:MallocSizeOf); r=emilio MallocSizeOf is similar to the existing HeapSizeOf trait from the heapsize crate. The only difference is that MallocSizeOf's malloc_size_of_children() function takes an additional MallocSizeOfFn argument, which is used to measure heap blocks. This extra argument makes MallocSizeOf match how Gecko's memory measurements work, and is required for Stylo to integrate with DMD. The patch also introduces a second trait, MallocSizeOfWithGuard, which is much the same as MallocSizeOf, but with a |guard| argument for the global style lock. Finally, the patch uses the new traits to measure a small amount of Stylo's memory usage. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because code is only for Gecko integration. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: aca09436b71e6defe007e1d17a9d79214d094a7b --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 1d5dc4e7ab75e8e0332922396b5b55ed67c4572e
2017-05-29 05:10:25 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
None,
);
// TODO(emilio): We're not measuring the size of the Arc<StyleSheetContents>
// allocation itself here.
StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops)
servo: Merge #17044 - Introduce and start using the MallocSizeOf trait (from nnethercote:MallocSizeOf); r=emilio MallocSizeOf is similar to the existing HeapSizeOf trait from the heapsize crate. The only difference is that MallocSizeOf's malloc_size_of_children() function takes an additional MallocSizeOfFn argument, which is used to measure heap blocks. This extra argument makes MallocSizeOf match how Gecko's memory measurements work, and is required for Stylo to integrate with DMD. The patch also introduces a second trait, MallocSizeOfWithGuard, which is much the same as MallocSizeOf, but with a |guard| argument for the global style lock. Finally, the patch uses the new traits to measure a small amount of Stylo's memory usage. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because code is only for Gecko integration. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: aca09436b71e6defe007e1d17a9d79214d094a7b --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 1d5dc4e7ab75e8e0332922396b5b55ed67c4572e
2017-05-29 05:10:25 +03:00
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin {
StylesheetContents::as_arc(&sheet).origin
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
sheet: &RawServoStyleSheetContents,
result: &mut nsAString,
) {
let contents = StylesheetContents::as_arc(&sheet);
let url_opt = contents.source_map_url.read();
if let Some(ref url) = *url_opt {
write!(result, "{}", url).unwrap();
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSheet_GetSourceURL(
sheet: &RawServoStyleSheetContents,
result: &mut nsAString,
) {
let contents = StylesheetContents::as_arc(&sheet);
let url_opt = contents.source_url.read();
if let Some(ref url) = *url_opt {
write!(result, "{}", url).unwrap();
}
}
fn read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
where
Locked<T>: HasArcFFI,
F: FnOnce(&T) -> R,
{
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
func(Locked::<T>::as_arc(&raw).read_with(&guard))
}
#[cfg(debug_assertions)]
unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
where
Locked<T>: HasArcFFI,
F: FnOnce(&T) -> R,
{
debug_assert!(is_main_thread() && !is_in_servo_traversal());
read_locked_arc(raw, func)
}
#[cfg(not(debug_assertions))]
unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
where
Locked<T>: HasArcFFI,
F: FnOnce(&T) -> R,
{
func(Locked::<T>::as_arc(&raw).read_unchecked())
}
fn write_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
where
Locked<T>: HasArcFFI,
F: FnOnce(&mut T) -> R,
{
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut guard = global_style_data.shared_lock.write();
func(Locked::<T>::as_arc(&raw).write_with(&mut guard))
}
#[no_mangle]
pub extern "C" fn Servo_CssRules_ListTypes(rules: &ServoCssRules, result: &mut nsTArray<usize>) {
read_locked_arc(rules, |rules: &CssRules| {
result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
})
}
#[no_mangle]
pub extern "C" fn Servo_CssRules_InsertRule(
rules: &ServoCssRules,
contents: &RawServoStyleSheetContents,
rule: &nsACString,
index: u32,
nested: bool,
loader: *mut Loader,
allow_import_rules: AllowImportRules,
gecko_stylesheet: *mut DomStyleSheet,
rule_type: *mut u16,
) -> nsresult {
let loader = if loader.is_null() {
None
} else {
Some(StylesheetLoader::new(
loader,
gecko_stylesheet,
ptr::null_mut(),
ptr::null_mut(),
))
};
let loader = loader
.as_ref()
.map(|loader| loader as &dyn StyleStylesheetLoader);
let rule = unsafe { rule.as_str_unchecked() };
let global_style_data = &*GLOBAL_STYLE_DATA;
let contents = StylesheetContents::as_arc(&contents);
let result = Locked::<CssRules>::as_arc(&rules).insert_rule(
&global_style_data.shared_lock,
rule,
contents,
index as usize,
nested,
loader,
allow_import_rules,
);
match result {
Ok(new_rule) => {
*unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
nsresult::NS_OK
},
Err(err) => err.into(),
}
}
#[no_mangle]
pub extern "C" fn Servo_CssRules_DeleteRule(rules: &ServoCssRules, index: u32) -> nsresult {
write_locked_arc(rules, |rules: &mut CssRules| {
match rules.remove_rule(index as usize) {
Ok(_) => nsresult::NS_OK,
Err(err) => err.into(),
}
})
}
macro_rules! impl_basic_rule_funcs_without_getter {
{ ($rule_type:ty, $raw_type:ty),
debug: $debug:ident,
to_css: $to_css:ident,
} => {
#[cfg(debug_assertions)]
#[no_mangle]
pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) {
read_locked_arc(rule, |rule: &$rule_type| {
write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap();
})
}
#[cfg(not(debug_assertions))]
#[no_mangle]
pub extern "C" fn $debug(_: &$raw_type, _: *mut nsACString) {
unreachable!()
}
#[no_mangle]
pub extern "C" fn $to_css(rule: &$raw_type, result: &mut nsAString) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rule = Locked::<$rule_type>::as_arc(&rule);
rule.read_with(&guard).to_css(&guard, result).unwrap();
}
}
}
macro_rules! impl_basic_rule_funcs {
{ ($name:ident, $rule_type:ty, $raw_type:ty),
getter: $getter:ident,
debug: $debug:ident,
to_css: $to_css:ident,
changed: $changed:ident,
} => {
#[no_mangle]
pub extern "C" fn $getter(
rules: &ServoCssRules,
index: u32,
line: *mut u32,
column: *mut u32,
) -> Strong<$raw_type> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
let index = index as usize;
if index >= rules.0.len() {
return Strong::null();
}
match rules.0[index] {
CssRule::$name(ref rule) => {
let location = rule.read_with(&guard).source_location;
*unsafe { line.as_mut().unwrap() } = location.line as u32;
*unsafe { column.as_mut().unwrap() } = location.column as u32;
rule.clone().into_strong()
},
_ => {
Strong::null()
}
}
}
#[no_mangle]
pub extern "C" fn $changed(
styleset: &RawServoStyleSet,
rule: &$raw_type,
sheet: &DomStyleSheet,
change_kind: RuleChangeKind,
) {
let mut data = PerDocumentStyleData::from_ffi(styleset).borrow_mut();
let data = &mut *data;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
// TODO(emilio): Would be nice not to deal with refcount bumps here,
// but it's probably not a huge deal.
let rule = Locked::<$rule_type>::as_arc(&rule);
let rule = CssRule::$name(rule.clone_arc());
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
data.stylist.rule_changed(&sheet, &rule, &guard, change_kind);
}
impl_basic_rule_funcs_without_getter! { ($rule_type, $raw_type),
debug: $debug,
to_css: $to_css,
}
}
}
macro_rules! impl_group_rule_funcs {
{ ($name:ident, $rule_type:ty, $raw_type:ty),
get_rules: $get_rules:ident,
$($basic:tt)+
} => {
impl_basic_rule_funcs! { ($name, $rule_type, $raw_type), $($basic)+ }
#[no_mangle]
pub extern "C" fn $get_rules(rule: &$raw_type) -> Strong<ServoCssRules> {
read_locked_arc(rule, |rule: &$rule_type| {
rule.rules.clone().into_strong()
})
}
}
}
impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule),
getter: Servo_CssRules_GetStyleRuleAt,
debug: Servo_StyleRule_Debug,
to_css: Servo_StyleRule_GetCssText,
changed: Servo_StyleSet_StyleRuleChanged,
}
impl_basic_rule_funcs! { (Import, ImportRule, RawServoImportRule),
getter: Servo_CssRules_GetImportRuleAt,
debug: Servo_ImportRule_Debug,
to_css: Servo_ImportRule_GetCssText,
changed: Servo_StyleSet_ImportRuleChanged,
}
impl_basic_rule_funcs_without_getter! { (Keyframe, RawServoKeyframe),
debug: Servo_Keyframe_Debug,
to_css: Servo_Keyframe_GetCssText,
}
impl_basic_rule_funcs! { (Keyframes, KeyframesRule, RawServoKeyframesRule),
getter: Servo_CssRules_GetKeyframesRuleAt,
debug: Servo_KeyframesRule_Debug,
to_css: Servo_KeyframesRule_GetCssText,
changed: Servo_StyleSet_KeyframesRuleChanged,
}
impl_group_rule_funcs! { (Media, MediaRule, RawServoMediaRule),
get_rules: Servo_MediaRule_GetRules,
getter: Servo_CssRules_GetMediaRuleAt,
debug: Servo_MediaRule_Debug,
to_css: Servo_MediaRule_GetCssText,
changed: Servo_StyleSet_MediaRuleChanged,
}
impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
getter: Servo_CssRules_GetNamespaceRuleAt,
debug: Servo_NamespaceRule_Debug,
to_css: Servo_NamespaceRule_GetCssText,
changed: Servo_StyleSet_NamespaceRuleChanged,
}
impl_basic_rule_funcs! { (Page, PageRule, RawServoPageRule),
getter: Servo_CssRules_GetPageRuleAt,
debug: Servo_PageRule_Debug,
to_css: Servo_PageRule_GetCssText,
changed: Servo_StyleSet_PageRuleChanged,
}
impl_group_rule_funcs! { (Supports, SupportsRule, RawServoSupportsRule),
get_rules: Servo_SupportsRule_GetRules,
getter: Servo_CssRules_GetSupportsRuleAt,
debug: Servo_SupportsRule_Debug,
to_css: Servo_SupportsRule_GetCssText,
changed: Servo_StyleSet_SupportsRuleChanged,
}
impl_group_rule_funcs! { (Document, DocumentRule, RawServoMozDocumentRule),
get_rules: Servo_MozDocumentRule_GetRules,
getter: Servo_CssRules_GetMozDocumentRuleAt,
debug: Servo_MozDocumentRule_Debug,
to_css: Servo_MozDocumentRule_GetCssText,
changed: Servo_StyleSet_MozDocumentRuleChanged,
}
impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, RawServoFontFeatureValuesRule),
getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
debug: Servo_FontFeatureValuesRule_Debug,
to_css: Servo_FontFeatureValuesRule_GetCssText,
changed: Servo_StyleSet_FontFeatureValuesRuleChanged,
}
impl_basic_rule_funcs! { (FontFace, FontFaceRule, RawServoFontFaceRule),
getter: Servo_CssRules_GetFontFaceRuleAt,
debug: Servo_FontFaceRule_Debug,
to_css: Servo_FontFaceRule_GetCssText,
changed: Servo_StyleSet_FontFaceRuleChanged,
}
impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, RawServoCounterStyleRule),
getter: Servo_CssRules_GetCounterStyleRuleAt,
debug: Servo_CounterStyleRule_Debug,
to_css: Servo_CounterStyleRule_GetCssText,
changed: Servo_StyleSet_CounterStyleRuleChanged,
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetStyle(
rule: &RawServoStyleRule,
) -> Strong<RawServoDeclarationBlock> {
read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into_strong())
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_SetStyle(
rule: &RawServoStyleRule,
declarations: &RawServoDeclarationBlock,
) {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
write_locked_arc(rule, |rule: &mut StyleRule| {
rule.block = declarations.clone_arc();
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorText(
rule: &RawServoStyleRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &StyleRule| {
rule.selectors.to_css(result).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorTextAtIndex(
rule: &RawServoStyleRule,
index: u32,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &StyleRule| {
let index = index as usize;
if index >= rule.selectors.0.len() {
return;
}
rule.selectors.0[index].to_css(result).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &RawServoStyleRule, count: *mut u32) {
read_locked_arc(rule, |rule: &StyleRule| {
*unsafe { count.as_mut().unwrap() } = rule.selectors.0.len() as u32;
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_GetSpecificityAtIndex(
rule: &RawServoStyleRule,
index: u32,
specificity: *mut u64,
) {
read_locked_arc(rule, |rule: &StyleRule| {
let specificity = unsafe { specificity.as_mut().unwrap() };
let index = index as usize;
if index >= rule.selectors.0.len() {
*specificity = 0;
return;
}
*specificity = rule.selectors.0[index].specificity() as u64;
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
rule: &RawServoStyleRule,
element: &RawGeckoElement,
index: u32,
pseudo_type: PseudoStyleType,
relevant_link_visited: bool,
) -> bool {
read_locked_arc(rule, |rule: &StyleRule| {
let index = index as usize;
if index >= rule.selectors.0.len() {
return false;
}
let selector = &rule.selectors.0[index];
let mut matching_mode = MatchingMode::Normal;
match PseudoElement::from_pseudo_type(pseudo_type) {
Some(pseudo) => {
// We need to make sure that the requested pseudo element type
// matches the selector pseudo element type before proceeding.
match selector.pseudo_element() {
Some(selector_pseudo) if *selector_pseudo == pseudo => {
matching_mode = MatchingMode::ForStatelessPseudoElement
},
_ => return false,
};
},
None => {
// Do not attempt to match if a pseudo element is requested and
// this is not a pseudo element selector, or vice versa.
if selector.has_pseudo_element() {
return false;
}
},
};
let element = GeckoElement(element);
let quirks_mode = element.as_node().owner_doc().quirks_mode();
let visited_mode = if relevant_link_visited {
VisitedHandlingMode::RelevantLinkVisited
} else {
VisitedHandlingMode::AllLinksUnvisited
};
let mut ctx =
MatchingContext::new_for_visited(matching_mode, None, None, visited_mode, quirks_mode);
matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleRule_SetSelectorText(
sheet: &RawServoStyleSheetContents,
rule: &RawServoStyleRule,
text: &nsAString,
) -> bool {
let value_str = text.to_string();
write_locked_arc(rule, |rule: &mut StyleRule| {
use style::selector_parser::SelectorParser;
let contents = StylesheetContents::as_arc(&sheet);
let namespaces = contents.namespaces.read();
let url_data = contents.url_data.read();
let parser = SelectorParser {
stylesheet_origin: contents.origin,
namespaces: &namespaces,
url_data: Some(&url_data),
};
let mut parser_input = ParserInput::new(&value_str);
match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input)) {
Ok(selectors) => {
rule.selectors = selectors;
true
},
Err(_) => false,
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_Closest(
element: &RawGeckoElement,
selectors: &RawServoSelectorList,
) -> *const RawGeckoElement {
use std::borrow::Borrow;
use style::dom_apis;
let element = GeckoElement(element);
let quirks_mode = element.as_node().owner_doc().quirks_mode();
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_Matches(
element: &RawGeckoElement,
selectors: &RawServoSelectorList,
) -> bool {
use std::borrow::Borrow;
use style::dom_apis;
let element = GeckoElement(element);
let quirks_mode = element.as_node().owner_doc().quirks_mode();
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
dom_apis::element_matches(&element, &selectors, quirks_mode)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
node: &RawGeckoNode,
selectors: &RawServoSelectorList,
may_use_invalidation: bool,
) -> *const RawGeckoElement {
use std::borrow::Borrow;
use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
let node = GeckoNode(node);
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
let mut result = None;
let may_use_invalidation = if may_use_invalidation {
MayUseInvalidation::Yes
} else {
MayUseInvalidation::No
};
dom_apis::query_selector::<GeckoElement, QueryFirst>(
node,
&selectors,
&mut result,
may_use_invalidation,
);
result.map_or(ptr::null(), |e| e.0)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
node: &RawGeckoNode,
selectors: &RawServoSelectorList,
content_list: *mut structs::nsSimpleContentList,
may_use_invalidation: bool,
) {
use std::borrow::Borrow;
use style::dom_apis::{self, MayUseInvalidation, QueryAll};
let node = GeckoNode(node);
let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
let mut result = SmallVec::new();
let may_use_invalidation = if may_use_invalidation {
MayUseInvalidation::Yes
} else {
MayUseInvalidation::No
};
dom_apis::query_selector::<GeckoElement, QueryAll>(
node,
&selectors,
&mut result,
may_use_invalidation,
);
if !result.is_empty() {
// NOTE(emilio): This relies on a slice of GeckoElement having the same
// memory representation than a slice of element pointers.
bindings::Gecko_ContentList_AppendAll(
content_list,
result.as_ptr() as *mut *const _,
result.len(),
)
}
}
#[no_mangle]
pub extern "C" fn Servo_ImportRule_GetHref(rule: &RawServoImportRule, result: &mut nsAString) {
read_locked_arc(rule, |rule: &ImportRule| {
write!(result, "{}", rule.url.as_str()).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_ImportRule_GetSheet(rule: &RawServoImportRule) -> *const DomStyleSheet {
read_locked_arc(rule, |rule: &ImportRule| {
rule.stylesheet.as_sheet().unwrap().raw() as *const DomStyleSheet
})
}
#[no_mangle]
pub extern "C" fn Servo_ImportRule_SetSheet(rule: &RawServoImportRule, sheet: *mut DomStyleSheet) {
write_locked_arc(rule, |rule: &mut ImportRule| {
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
rule.stylesheet = ImportSheet::new(sheet);
})
}
#[no_mangle]
pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &RawServoKeyframe, result: &mut nsAString) {
read_locked_arc(keyframe, |keyframe: &Keyframe| {
keyframe
.selector
.to_css(&mut CssWriter::new(result))
.unwrap()
})
}
#[no_mangle]
pub extern "C" fn Servo_Keyframe_SetKeyText(
keyframe: &RawServoKeyframe,
text: &nsACString,
) -> bool {
let text = unsafe { text.as_str_unchecked() };
let mut input = ParserInput::new(&text);
if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
keyframe.selector = selector;
});
true
} else {
false
}
}
#[no_mangle]
pub extern "C" fn Servo_Keyframe_GetStyle(
keyframe: &RawServoKeyframe,
) -> Strong<RawServoDeclarationBlock> {
read_locked_arc(keyframe, |keyframe: &Keyframe| {
keyframe.block.clone().into_strong()
})
}
#[no_mangle]
pub extern "C" fn Servo_Keyframe_SetStyle(
keyframe: &RawServoKeyframe,
declarations: &RawServoDeclarationBlock,
) {
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
keyframe.block = declarations.clone_arc();
})
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_GetName(rule: &RawServoKeyframesRule) -> *mut nsAtom {
read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
}
#[no_mangle]
pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
rule: &RawServoKeyframesRule,
name: *mut nsAtom,
) {
write_locked_arc(rule, |rule: &mut KeyframesRule| {
rule.name = KeyframesName::Ident(CustomIdent(Atom::from_addrefed(name)));
})
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &RawServoKeyframesRule) -> u32 {
read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
rule: &RawServoKeyframesRule,
index: u32,
line: *mut u32,
column: *mut u32,
) -> Strong<RawServoKeyframe> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let key = Locked::<KeyframesRule>::as_arc(&rule)
.read_with(&guard)
.keyframes[index as usize]
.clone();
let location = key.read_with(&guard).source_location;
*unsafe { line.as_mut().unwrap() } = location.line as u32;
*unsafe { column.as_mut().unwrap() } = location.column as u32;
key.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_FindRule(
rule: &RawServoKeyframesRule,
key: &nsACString,
) -> u32 {
let key = unsafe { key.as_str_unchecked() };
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
Locked::<KeyframesRule>::as_arc(&rule)
.read_with(&guard)
.find_rule(&guard, key)
.map(|index| index as u32)
.unwrap_or(u32::max_value())
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_AppendRule(
rule: &RawServoKeyframesRule,
contents: &RawServoStyleSheetContents,
css: &nsACString,
) -> bool {
let css = unsafe { css.as_str_unchecked() };
let contents = StylesheetContents::as_arc(&contents);
let global_style_data = &*GLOBAL_STYLE_DATA;
match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
Ok(keyframe) => {
write_locked_arc(rule, |rule: &mut KeyframesRule| {
rule.keyframes.push(keyframe);
});
true
},
Err(..) => false,
}
}
#[no_mangle]
pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &RawServoKeyframesRule, index: u32) {
write_locked_arc(rule, |rule: &mut KeyframesRule| {
rule.keyframes.remove(index as usize);
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaRule_GetMedia(rule: &RawServoMediaRule) -> Strong<RawServoMediaList> {
read_locked_arc(rule, |rule: &MediaRule| {
rule.media_queries.clone().into_strong()
})
}
#[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &RawServoNamespaceRule) -> *mut nsAtom {
read_locked_arc(rule, |rule: &NamespaceRule| {
rule.prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
})
}
#[no_mangle]
pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &RawServoNamespaceRule) -> *mut nsAtom {
read_locked_arc(rule, |rule: &NamespaceRule| rule.url.0.as_ptr())
}
#[no_mangle]
pub extern "C" fn Servo_PageRule_GetStyle(
rule: &RawServoPageRule,
) -> Strong<RawServoDeclarationBlock> {
read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into_strong())
}
#[no_mangle]
pub extern "C" fn Servo_PageRule_SetStyle(
rule: &RawServoPageRule,
declarations: &RawServoDeclarationBlock,
) {
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
write_locked_arc(rule, |rule: &mut PageRule| {
rule.block = declarations.clone_arc();
})
}
#[no_mangle]
pub extern "C" fn Servo_SupportsRule_GetConditionText(
rule: &RawServoSupportsRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &SupportsRule| {
rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_MozDocumentRule_GetConditionText(
rule: &RawServoMozDocumentRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &DocumentRule| {
rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
rule: &RawServoFontFeatureValuesRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
rule.font_family_to_css(&mut CssWriter::new(result))
.unwrap()
})
}
#[no_mangle]
pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
rule: &RawServoFontFeatureValuesRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
rule.value_to_css(&mut CssWriter::new(result)).unwrap();
})
}
#[no_mangle]
pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<RawServoFontFaceRule> {
let global_style_data = &*GLOBAL_STYLE_DATA;
// XXX This is not great. We should split FontFace descriptor data
// from the rule, so that we don't need to create the rule like this
// and the descriptor data itself can be hold in UniquePtr from the
// Gecko side. See bug 1450904.
Arc::new(
global_style_data
.shared_lock
.wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 })),
)
.into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
rule: &RawServoFontFaceRule,
) -> Strong<RawServoFontFaceRule> {
let clone = read_locked_arc(rule, |rule: &FontFaceRule| rule.clone());
let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(global_style_data.shared_lock.wrap(clone)).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
rule: &RawServoFontFaceRule,
line: *mut u32,
column: *mut u32,
) {
read_locked_arc(rule, |rule: &FontFaceRule| {
let location = rule.source_location;
*line.as_mut().unwrap() = location.line as u32;
*column.as_mut().unwrap() = location.column as u32;
});
}
macro_rules! apply_font_desc_list {
($apply_macro:ident) => {
$apply_macro! {
valid: [
eCSSFontDesc_Family => family,
eCSSFontDesc_Style => style,
eCSSFontDesc_Weight => weight,
eCSSFontDesc_Stretch => stretch,
eCSSFontDesc_Src => sources,
eCSSFontDesc_UnicodeRange => unicode_range,
eCSSFontDesc_FontFeatureSettings => feature_settings,
eCSSFontDesc_FontVariationSettings => variation_settings,
eCSSFontDesc_FontLanguageOverride => language_override,
eCSSFontDesc_Display => display,
]
invalid: [
eCSSFontDesc_UNKNOWN,
eCSSFontDesc_COUNT,
]
}
};
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &RawServoFontFaceRule) -> u32 {
read_locked_arc(rule, |rule: &FontFaceRule| {
let mut result = 0;
macro_rules! count_values {
(
valid: [$($v_enum_name:ident => $field:ident,)*]
invalid: [$($i_enum_name:ident,)*]
) => {
$(if rule.$field.is_some() {
result += 1;
})*
}
}
apply_font_desc_list!(count_values);
result
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
rule: &RawServoFontFaceRule,
index: u32,
) -> nsCSSFontDesc {
read_locked_arc(rule, |rule: &FontFaceRule| {
let mut count = 0;
macro_rules! lookup_index {
(
valid: [$($v_enum_name:ident => $field:ident,)*]
invalid: [$($i_enum_name:ident,)*]
) => {
$(if rule.$field.is_some() {
count += 1;
if count - 1 == index {
return nsCSSFontDesc::$v_enum_name;
}
})*
}
}
apply_font_desc_list!(lookup_index);
return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
rule: &RawServoFontFaceRule,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &FontFaceRule| {
rule.decl_to_css(result).unwrap();
})
}
macro_rules! simple_font_descriptor_getter_impl {
($rule:ident, $out:ident, $field:ident, $compute:ident) => {
read_locked_arc($rule, |rule: &FontFaceRule| {
match rule.$field {
None => return false,
Some(ref f) => *$out = f.$compute(),
}
true
})
};
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFontWeight(
rule: &RawServoFontFaceRule,
out: &mut font_face::ComputedFontWeightRange,
) -> bool {
simple_font_descriptor_getter_impl!(rule, out, weight, compute)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStretch(
rule: &RawServoFontFaceRule,
out: &mut font_face::ComputedFontStretchRange,
) -> bool {
simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStyle(
rule: &RawServoFontFaceRule,
out: &mut font_face::ComputedFontStyleDescriptor,
) -> bool {
simple_font_descriptor_getter_impl!(rule, out, style, compute)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFontDisplay(
rule: &RawServoFontFaceRule,
out: &mut font_face::FontDisplay,
) -> bool {
simple_font_descriptor_getter_impl!(rule, out, display, clone)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
rule: &RawServoFontFaceRule,
out: &mut computed::FontLanguageOverride,
) -> bool {
simple_font_descriptor_getter_impl!(rule, out, language_override, compute_non_system)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
rule: &RawServoFontFaceRule,
) -> *mut nsAtom {
read_locked_arc(rule, |rule: &FontFaceRule| {
// TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
// here, and remove the null-checks in Gecko?
rule.family
.as_ref()
.map_or(ptr::null_mut(), |f| f.name.as_ptr())
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
rule: &RawServoFontFaceRule,
out_len: *mut usize,
) -> *const UnicodeRange {
*out_len = 0;
read_locked_arc(rule, |rule: &FontFaceRule| {
let ranges = match rule.unicode_range {
Some(ref ranges) => ranges,
None => return ptr::null(),
};
*out_len = ranges.len();
ranges.as_ptr() as *const _
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
rule: &RawServoFontFaceRule,
out: *mut nsTArray<FontFaceSourceListComponent>,
) {
let out = &mut *out;
read_locked_arc(rule, |rule: &FontFaceRule| {
let sources = match rule.sources {
Some(ref s) => s,
None => return,
};
let len = sources.iter().fold(0, |acc, src| {
acc + match *src {
// Each format hint takes one position in the array of mSrc.
Source::Url(ref url) => url.format_hints.len() + 1,
Source::Local(_) => 1,
}
});
out.set_len(len as u32);
let mut iter = out.iter_mut();
{
let mut set_next = |component: FontFaceSourceListComponent| {
*iter.next().expect("miscalculated length") = component;
};
for source in sources.iter() {
match *source {
Source::Url(ref url) => {
Bug 1552708 - Use cbindgen for URIs. r=heycam This doesn't clean up as much as a whole, but it's a step in the right direction. In particular, it allows us to start using simple bindings for: * Filters * Shapes and images, almost. Need to: * Get rid of the complex -moz- gradient parsing (let layout.css.simple-moz-gradient.enabled get to release). * Counters, almost. Need to: * Share the Attr representation with Gecko, by not using Option<>. * Just another variant should be enough (ContentItem::{Attr,Prefixedattr}, maybe). Which in turn allows us to remove a whole lot of bindings in followups to this. The setup changes a bit. This also removes the double pointer I complained about while reviewing the shared UA sheet patches. The old setup is: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * UrlValueSource * Arc<CssUrlData> * load id * resolved uri * CORS mode. * ... ``` The new one removes the double reference to the url data via URLValue, and looks like: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * CorsMode * LoadData * load id * resolved URI ``` The LoadData is the only mutable bit that C++ can change, and is not used from Rust. Ideally, in the future, we could just use rust-url to resolve the URL after parsing or something, and make it all immutable. Maybe. I've verified that this approach still works with the UA sheet patches (via the LoadDataSource::Lazy). The reordering of mWillChange is to avoid nsStyleDisplay from going over the size limit. We want to split it up anyway in bug 1552587, but mBinding gains a tag member, which means that we were having a bit of extra padding. One thing I want to explore is to see if we can abuse rustc's non-zero optimizations to predict the layout from C++, but that's something to explore at some other point in time and with a lot of care and help from Michael (who sits next to me and works on rustc ;)). Differential Revision: https://phabricator.services.mozilla.com/D31742
2019-05-27 14:45:12 +03:00
set_next(FontFaceSourceListComponent::Url(&url.url));
for hint in url.format_hints.iter() {
set_next(FontFaceSourceListComponent::FormatHint {
length: hint.len(),
utf8_bytes: hint.as_ptr(),
});
}
},
Source::Local(ref name) => {
set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
},
}
}
}
assert!(iter.next().is_none(), "miscalculated");
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
rule: &RawServoFontFaceRule,
variations: *mut nsTArray<structs::gfxFontVariation>,
) {
read_locked_arc(rule, |rule: &FontFaceRule| {
let source_variations = match rule.variation_settings {
Some(ref v) => v,
None => return,
};
(*variations).set_len(source_variations.0.len() as u32);
for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
*target = structs::gfxFontVariation {
mTag: source.tag.0,
mValue: source.value.get(),
};
}
});
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
rule: &RawServoFontFaceRule,
features: *mut nsTArray<structs::gfxFontFeature>,
) {
read_locked_arc(rule, |rule: &FontFaceRule| {
let source_features = match rule.feature_settings {
Some(ref v) => v,
None => return,
};
(*features).set_len(source_features.0.len() as u32);
for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
*target = structs::gfxFontFeature {
mTag: source.tag.0,
mValue: source.value.value() as u32,
};
}
});
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
rule: &RawServoFontFaceRule,
desc: nsCSSFontDesc,
result: &mut nsAString,
) {
read_locked_arc(rule, |rule: &FontFaceRule| {
let mut writer = CssWriter::new(result);
macro_rules! to_css_text {
(
valid: [$($v_enum_name:ident => $field:ident,)*]
invalid: [$($i_enum_name:ident,)*]
) => {
match desc {
$(
nsCSSFontDesc::$v_enum_name => {
if let Some(ref value) = rule.$field {
value.to_css(&mut writer).unwrap();
}
}
)*
$(
nsCSSFontDesc::$i_enum_name => {
debug_assert!(false, "not a valid font descriptor");
}
)*
}
}
}
apply_font_desc_list!(to_css_text)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
rule: &RawServoFontFaceRule,
desc: nsCSSFontDesc,
value: &nsACString,
data: *mut URLExtraData,
out_changed: *mut bool,
) -> bool {
let value = value.as_str_unchecked();
let mut input = ParserInput::new(&value);
let mut parser = Parser::new(&mut input);
let url_data = UrlExtraData::from_ptr_ref(&data);
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::FontFace),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
write_locked_arc(rule, |rule: &mut FontFaceRule| {
macro_rules! to_css_text {
(
valid: [$($v_enum_name:ident => $field:ident,)*]
invalid: [$($i_enum_name:ident,)*]
) => {
match desc {
$(
nsCSSFontDesc::$v_enum_name => {
if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
let result = Some(value);
*out_changed = result != rule.$field;
rule.$field = result;
true
} else {
false
}
}
)*
$(
nsCSSFontDesc::$i_enum_name => {
debug_assert!(false, "not a valid font descriptor");
false
}
)*
}
}
}
apply_font_desc_list!(to_css_text)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
rule: &RawServoFontFaceRule,
desc: nsCSSFontDesc,
) {
write_locked_arc(rule, |rule: &mut FontFaceRule| {
macro_rules! reset_desc {
(
valid: [$($v_enum_name:ident => $field:ident,)*]
invalid: [$($i_enum_name:ident,)*]
) => {
match desc {
$(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
$(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
}
}
}
apply_font_desc_list!(reset_desc)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
rule: &RawServoCounterStyleRule,
) -> *mut nsAtom {
read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
rule: &RawServoCounterStyleRule,
value: &nsACString,
) -> bool {
let value = value.as_str_unchecked();
let mut input = ParserInput::new(&value);
let mut parser = Parser::new(&mut input);
match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
Ok(name) => {
write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
true
},
Err(_) => false,
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
rule: &RawServoCounterStyleRule,
) -> u32 {
read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
}
fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
match *s {
counter_style::Symbol::String(ref s) => nsString::from(&**s),
counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
}
}
// TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
rule: &RawServoCounterStyleRule,
width: &mut i32,
symbol: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
let pad = match rule.pad() {
Some(pad) => pad,
None => return false,
};
*width = pad.0.value();
*symbol = symbol_to_string(&pad.1);
true
})
}
fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
let s = match s {
Some(s) => s,
None => return false,
};
*out = symbol_to_string(s);
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
rule: &RawServoCounterStyleRule,
out: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
get_symbol(rule.prefix(), out)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
rule: &RawServoCounterStyleRule,
out: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
get_symbol(rule.suffix(), out)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
rule: &RawServoCounterStyleRule,
prefix: &mut nsString,
suffix: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
let negative = match rule.negative() {
Some(n) => n,
None => return false,
};
*prefix = symbol_to_string(&negative.0);
*suffix = match negative.1 {
Some(ref s) => symbol_to_string(s),
None => nsString::new(),
};
true
})
}
#[repr(u8)]
pub enum IsOrdinalInRange {
Auto,
InRange,
NotInRange,
NoOrdinalSpecified,
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
rule: &RawServoCounterStyleRule,
ordinal: i32,
) -> IsOrdinalInRange {
use style::counter_style::CounterBound;
read_locked_arc(rule, |rule: &CounterStyleRule| {
let range = match rule.range() {
Some(r) => r,
None => return IsOrdinalInRange::NoOrdinalSpecified,
};
if range.0.is_empty() {
return IsOrdinalInRange::Auto;
}
let in_range = range.0.iter().any(|r| {
if let CounterBound::Integer(start) = r.start {
if start.value() > ordinal {
return false;
}
}
if let CounterBound::Integer(end) = r.end {
if end.value() < ordinal {
return false;
}
}
true
});
if in_range {
IsOrdinalInRange::InRange
} else {
IsOrdinalInRange::NotInRange
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
rule: &RawServoCounterStyleRule,
symbols: &mut style::OwnedSlice<nsString>,
) {
read_locked_arc(rule, |rule: &CounterStyleRule| {
*symbols = match rule.symbols() {
Some(s) => s.0.iter().map(symbol_to_string).collect(),
None => style::OwnedSlice::default(),
};
})
}
#[repr(C)]
pub struct AdditiveSymbol {
pub weight: i32,
pub symbol: nsString,
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
rule: &RawServoCounterStyleRule,
symbols: &mut style::OwnedSlice<AdditiveSymbol>,
) {
read_locked_arc(rule, |rule: &CounterStyleRule| {
*symbols = match rule.additive_symbols() {
Some(s) => {
s.0.iter()
.map(|s| AdditiveSymbol {
weight: s.weight.value(),
symbol: symbol_to_string(&s.symbol),
})
.collect()
},
None => style::OwnedSlice::default(),
};
})
}
#[repr(C, u8)]
pub enum CounterSpeakAs {
None,
Auto,
Bullets,
Numbers,
Words,
Ident(*mut nsAtom),
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
rule: &RawServoCounterStyleRule,
out: &mut CounterSpeakAs,
) {
use style::counter_style::SpeakAs;
*out = read_locked_arc(rule, |rule: &CounterStyleRule| {
let speak_as = match rule.speak_as() {
Some(s) => s,
None => return CounterSpeakAs::None,
};
match *speak_as {
SpeakAs::Auto => CounterSpeakAs::Auto,
SpeakAs::Bullets => CounterSpeakAs::Bullets,
SpeakAs::Numbers => CounterSpeakAs::Numbers,
SpeakAs::Words => CounterSpeakAs::Words,
SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
}
});
}
#[repr(u8)]
pub enum CounterSystem {
Cyclic = 0,
Numeric,
Alphabetic,
Symbolic,
Additive,
Fixed,
Extends,
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
rule: &RawServoCounterStyleRule,
) -> CounterSystem {
use style::counter_style::System;
read_locked_arc(rule, |rule: &CounterStyleRule| {
match *rule.resolved_system() {
System::Cyclic => CounterSystem::Cyclic,
System::Numeric => CounterSystem::Numeric,
System::Alphabetic => CounterSystem::Alphabetic,
System::Symbolic => CounterSystem::Symbolic,
System::Additive => CounterSystem::Additive,
System::Fixed { .. } => CounterSystem::Fixed,
System::Extends(_) => CounterSystem::Extends,
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
rule: &RawServoCounterStyleRule,
) -> *mut nsAtom {
read_locked_arc(rule, |rule: &CounterStyleRule| {
match *rule.resolved_system() {
counter_style::System::Extends(ref name) => name.0.as_ptr(),
_ => {
debug_assert!(false, "Not extends system");
ptr::null_mut()
},
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
rule: &RawServoCounterStyleRule,
) -> i32 {
read_locked_arc(rule, |rule: &CounterStyleRule| {
match *rule.resolved_system() {
counter_style::System::Fixed { first_symbol_value } => {
first_symbol_value.map_or(1, |v| v.value())
},
_ => {
debug_assert!(false, "Not fixed system");
0
},
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
rule: &RawServoCounterStyleRule,
) -> *mut nsAtom {
read_locked_arc(rule, |rule: &CounterStyleRule| {
rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
})
}
macro_rules! counter_style_descriptors {
{
valid: [
$($desc:ident => $getter:ident / $setter:ident,)+
]
invalid: [
$($i_desc:ident,)+
]
} => {
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
rule: &RawServoCounterStyleRule,
desc: nsCSSCounterDesc,
result: &mut nsAString,
) {
let mut writer = CssWriter::new(result);
read_locked_arc(rule, |rule: &CounterStyleRule| {
match desc {
$(nsCSSCounterDesc::$desc => {
if let Some(value) = rule.$getter() {
value.to_css(&mut writer).unwrap();
}
})+
$(nsCSSCounterDesc::$i_desc => unreachable!(),)+
}
});
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
rule: &RawServoCounterStyleRule,
desc: nsCSSCounterDesc,
value: &nsACString,
) -> bool {
let value = value.as_str_unchecked();
let mut input = ParserInput::new(&value);
let mut parser = Parser::new(&mut input);
let url_data = dummy_url_data();
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::CounterStyle),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
write_locked_arc(rule, |rule: &mut CounterStyleRule| {
match desc {
$(nsCSSCounterDesc::$desc => {
match parser.parse_entirely(|i| Parse::parse(&context, i)) {
Ok(value) => rule.$setter(value),
Err(_) => false,
}
})+
$(nsCSSCounterDesc::$i_desc => unreachable!(),)+
}
})
}
}
}
counter_style_descriptors! {
valid: [
eCSSCounterDesc_System => system / set_system,
eCSSCounterDesc_Symbols => symbols / set_symbols,
eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
eCSSCounterDesc_Negative => negative / set_negative,
eCSSCounterDesc_Prefix => prefix / set_prefix,
eCSSCounterDesc_Suffix => suffix / set_suffix,
eCSSCounterDesc_Range => range / set_range,
eCSSCounterDesc_Pad => pad / set_pad,
eCSSCounterDesc_Fallback => fallback / set_fallback,
eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
]
invalid: [
eCSSCounterDesc_UNKNOWN,
eCSSCounterDesc_COUNT,
]
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
parent_style_or_null: Option<&ComputedValues>,
pseudo: PseudoStyleType,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let guards = StylesheetGuards::same(&guard);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
debug_assert!(pseudo.is_anon_box());
let metrics = get_metrics_provider_for_product();
// If the pseudo element is PageContent, we should append the precomputed
// pseudo element declerations with specified page rules.
let page_decls = match pseudo {
PseudoElement::PageContent => {
let mut declarations = vec![];
let iter = data.stylist.iter_extra_data_origins_rev();
for (data, origin) in iter {
let level = match origin {
Origin::UserAgent => CascadeLevel::UANormal,
Origin::User => CascadeLevel::UserNormal,
Origin::Author => CascadeLevel::same_tree_author_normal(),
};
for rule in data.pages.iter() {
declarations.push(ApplicableDeclarationBlock::from_declarations(
rule.read_with(level.guard(&guards)).block.clone(),
level,
));
}
}
Some(declarations)
},
_ => None,
};
let rule_node = data
.stylist
.rule_node_for_precomputed_pseudo(&guards, &pseudo, page_decls);
data.stylist
.precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
&guards,
&pseudo,
parent_style_or_null.map(|x| &*x),
&metrics,
rule_node,
)
.into()
}
#[no_mangle]
pub extern "C" fn Servo_ResolvePseudoStyle(
element: &RawGeckoElement,
pseudo_type: PseudoStyleType,
is_probe: bool,
inherited_style: Option<&ComputedValues>,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
debug!(
"Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
element,
PseudoElement::from_pseudo_type(pseudo_type),
is_probe
);
let data = element.borrow_data();
let data = match data.as_ref() {
Some(data) if data.has_styles() => data,
_ => {
// FIXME(bholley, emilio): Assert against this.
//
// Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
// which goes and does a bunch of work involving style resolution.
//
// Bug 1403865 tracks fixing it, and potentially adding an assert
// here instead.
warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
return if is_probe {
Strong::null()
} else {
doc_data.default_computed_values().clone().into()
};
},
};
let pseudo = PseudoElement::from_pseudo_type(pseudo_type)
.expect("ResolvePseudoStyle with a non-pseudo?");
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let style = get_pseudo_style(
&guard,
element,
&pseudo,
RuleInclusion::All,
&data.styles,
inherited_style,
&*doc_data,
is_probe,
/* matching_func = */ None,
);
match style {
Some(s) => s.into(),
None => {
debug_assert!(is_probe);
Strong::null()
},
}
}
fn debug_atom_array(atoms: &AtomArray) -> String {
let mut result = String::from("[");
for atom in atoms.iter() {
if atom.mRawPtr.is_null() {
result += "(null), ";
} else {
let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
write!(result, "{}, ", atom).unwrap();
}
}
result.push(']');
result
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
element: &RawGeckoElement,
pseudo_tag: *mut nsAtom,
inherited_style: &ComputedValues,
input_word: &AtomArray,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
let element = GeckoElement(element);
let data = element
.borrow_data()
.expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
let pseudo = unsafe {
Atom::with(pseudo_tag, |atom| {
PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
})
.expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
};
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
debug!(
"ResolveXULTreePseudoStyle: {:?} {:?} {}",
element,
pseudo,
debug_atom_array(input_word)
);
let matching_fn = |pseudo: &PseudoElement| {
let args = pseudo
.tree_pseudo_args()
.expect("Not a tree pseudo-element?");
args.iter()
.all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
get_pseudo_style(
&guard,
element,
&pseudo,
RuleInclusion::All,
&data.styles,
Some(inherited_style),
&*doc_data,
/* is_probe = */ false,
Some(&matching_fn),
)
.unwrap()
.into()
}
#[no_mangle]
pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
let element = GeckoElement(element);
debug!("Servo_SetExplicitStyle: {:?}", element);
// We only support this API for initial styling. There's no reason it couldn't
// work for other things, we just haven't had a reason to do so.
debug_assert!(!element.has_data());
let mut data = unsafe { element.ensure_data() };
data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc());
}
fn get_pseudo_style(
guard: &SharedRwLockReadGuard,
element: GeckoElement,
pseudo: &PseudoElement,
rule_inclusion: RuleInclusion,
styles: &ElementStyles,
inherited_styles: Option<&ComputedValues>,
doc_data: &PerDocumentStyleDataImpl,
is_probe: bool,
matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
) -> Option<Arc<ComputedValues>> {
let style = match pseudo.cascade_type() {
PseudoElementCascadeType::Eager => {
match *pseudo {
PseudoElement::FirstLetter => {
servo: Merge #19842 - style: Cleanup a bit the cascade (from emilio:cascade-cleanup); r=nox,jryans This makes an element available in StyleAdjuster, and uses it to replace some of our CascadeFlags (the ones that don't represent restrictions on what's actually cascaded, actually). That fixes handwaviness in the handling of those flags from style reparenting, and code duplication to handle tricky stuff like :visited. There are a number of other changes that are worth noticing: * skip_root_and_item_based_display_fixup is renamed to skip_item_display_fixup: TElement::is_root() already implies being the document element, which by definition is not native anonymous and not a pseudo-element. Thus, you never get fixed-up if your NAC or a pseudo, which is what the code tried to avoid, so the only fixup with a point is the item one, which is necessary. * The pseudo-element probing code was refactored to return early a Option::<CascadeInputs>::None, which is nicer than what it was doing. * The visited_links_enabled check has moved to selector-matching time. The rest of the checks aren't based on whether the element is a link, or are properly guarded by parent_style.visited_style().is_some() or visited_rules.is_some(). Thus you can transitively infer that no element will end up with a :visited style, not even from style reparenting. Anyway, the underlying reason why I want the element in StyleAdjuster is because we're going to implement an adjustment in there depending on the tag of the element (converting display: contents to display: none depending on the tag), so computing that information eagerly, including a hash lookup, wouldn't be nice. See each commit for details. Source-Repo: https://github.com/servo/servo Source-Revision: 02331617b9bd7a379b05f7daa7ad09a44c27504c --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : dceeca4961762c9f7414007c83ceed03e00c720b
2018-01-23 15:30:51 +03:00
styles.pseudos.get(&pseudo).map(|pseudo_styles| {
// inherited_styles can be None when doing lazy resolution
// (e.g. for computed style) or when probing. In that case
// we just inherit from our element, which is what Gecko
// does in that situation. What should actually happen in
// the computed style case is a bit unclear.
let inherited_styles = inherited_styles.unwrap_or(styles.primary());
let guards = StylesheetGuards::same(guard);
let metrics = get_metrics_provider_for_product();
let inputs = CascadeInputs::new_from_style(pseudo_styles);
servo: Merge #19842 - style: Cleanup a bit the cascade (from emilio:cascade-cleanup); r=nox,jryans This makes an element available in StyleAdjuster, and uses it to replace some of our CascadeFlags (the ones that don't represent restrictions on what's actually cascaded, actually). That fixes handwaviness in the handling of those flags from style reparenting, and code duplication to handle tricky stuff like :visited. There are a number of other changes that are worth noticing: * skip_root_and_item_based_display_fixup is renamed to skip_item_display_fixup: TElement::is_root() already implies being the document element, which by definition is not native anonymous and not a pseudo-element. Thus, you never get fixed-up if your NAC or a pseudo, which is what the code tried to avoid, so the only fixup with a point is the item one, which is necessary. * The pseudo-element probing code was refactored to return early a Option::<CascadeInputs>::None, which is nicer than what it was doing. * The visited_links_enabled check has moved to selector-matching time. The rest of the checks aren't based on whether the element is a link, or are properly guarded by parent_style.visited_style().is_some() or visited_rules.is_some(). Thus you can transitively infer that no element will end up with a :visited style, not even from style reparenting. Anyway, the underlying reason why I want the element in StyleAdjuster is because we're going to implement an adjustment in there depending on the tag of the element (converting display: contents to display: none depending on the tag), so computing that information eagerly, including a hash lookup, wouldn't be nice. See each commit for details. Source-Repo: https://github.com/servo/servo Source-Revision: 02331617b9bd7a379b05f7daa7ad09a44c27504c --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : dceeca4961762c9f7414007c83ceed03e00c720b
2018-01-23 15:30:51 +03:00
doc_data.stylist.compute_pseudo_element_style_with_inputs(
inputs,
pseudo,
&guards,
Some(inherited_styles),
&metrics,
Some(element),
)
})
},
_ => {
// Unfortunately, we can't assert that inherited_styles, if
// present, is pointer-equal to styles.primary(), or even
// equal in any meaningful way. The way it can fail is as
// follows. Say we append an element with a ::before,
// ::after, or ::first-line to a parent with a ::first-line,
// such that the element ends up on the first line of the
// parent (e.g. it's an inline-block in the case it has a
// ::first-line, or any container in the ::before/::after
// cases). Then gecko will update its frame's style to
// inherit from the parent's ::first-line. The next time we
// try to get the ::before/::after/::first-line style for
// the kid, we'll likely pass in the frame's style as
// inherited_styles, but that's not pointer-identical to
// styles.primary(), because it got reparented.
//
// Now in practice this turns out to be OK, because all the
// cases in which there's a mismatch go ahead and reparent
// styles again as needed to make sure the ::first-line
// affects all the things it should affect. But it makes it
// impossible to assert anything about the two styles
// matching here, unfortunately.
styles.pseudos.get(&pseudo).cloned()
},
}
},
PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
PseudoElementCascadeType::Lazy => {
debug_assert!(
inherited_styles.is_none() ||
ptr::eq(inherited_styles.unwrap(), &**styles.primary())
);
let base = if pseudo.inherits_from_default_values() {
doc_data.default_computed_values()
} else {
styles.primary()
};
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let guards = StylesheetGuards::same(guard);
let metrics = get_metrics_provider_for_product();
doc_data.stylist.lazily_compute_pseudo_element_style(
&guards,
element,
&pseudo,
rule_inclusion,
base,
is_probe,
&metrics,
matching_func,
)
},
};
if is_probe {
return style;
}
Some(style.unwrap_or_else(|| {
StyleBuilder::for_inheritance(
doc_data.stylist.device(),
Some(styles.primary()),
Some(pseudo),
)
.build()
}))
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
raw_data: &RawServoStyleSet,
pseudo: PseudoStyleType,
parent_style_context: Option<&ComputedValues>,
target: structs::InheritTarget,
) -> Strong<ComputedValues> {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let for_text = target == structs::InheritTarget::Text;
let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
debug_assert!(pseudo.is_anon_box());
let mut style =
StyleBuilder::for_inheritance(data.stylist.device(), parent_style_context, Some(&pseudo));
if for_text {
StyleAdjuster::new(&mut style).adjust_for_text();
}
style.build().into()
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
values: &ComputedValues,
) -> bool {
let b = values.get_box();
b.specifies_animations() || b.specifies_transitions()
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
values: &ComputedValues,
rules: &mut nsTArray<*const RawServoStyleRule>,
) {
let rule_node = match values.rules {
Some(ref r) => r,
None => return,
};
let mut result = SmallVec::<[_; 10]>::new();
for node in rule_node.self_and_ancestors() {
let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
Some(rule) => rule,
_ => continue,
};
servo: Merge #18337 - Make the order of rules in DevTools be the specificity order (from kuoe0:make-the-order-of-rules-in-DevTools-be-the-specificity-order); r=emilio We insert rules with any important declaration into rule tree twice, one for the normal level and another for the important level. And when we fetch them from rule tree, we skip the important one to make the order be the specificity order. <!-- 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 [Bug 1391198](https://bugzilla.mozilla.org/show_bug.cgi?id=1391198) <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because test cases already in gecko <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: af52f5394a259edf52a92c0f96a5d6069a1041d5 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : eb040e38caa5689211498d7d7c53f9bbc24d52ed
2017-09-01 12:15:21 +03:00
// For the rules with any important declaration, we insert them into
// rule tree twice, one for normal level and another for important
// level. So, we skip the important one to keep the specificity order of
// rules.
if node.importance().important() {
servo: Merge #18337 - Make the order of rules in DevTools be the specificity order (from kuoe0:make-the-order-of-rules-in-DevTools-be-the-specificity-order); r=emilio We insert rules with any important declaration into rule tree twice, one for the normal level and another for the important level. And when we fetch them from rule tree, we skip the important one to make the order be the specificity order. <!-- 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 [Bug 1391198](https://bugzilla.mozilla.org/show_bug.cgi?id=1391198) <!-- Either: --> - [ ] There are tests for these changes OR - [X] These changes do not require tests because test cases already in gecko <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: af52f5394a259edf52a92c0f96a5d6069a1041d5 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : eb040e38caa5689211498d7d7c53f9bbc24d52ed
2017-09-01 12:15:21 +03:00
continue;
}
result.push(style_rule);
}
rules.assign_from_iter_pod(result.into_iter().map(|src| {
src.with_arc(|a| {
a.with_raw_offset_arc(|arc| *Locked::<StyleRule>::arc_as_borrowed(arc) as *const _)
})
}))
}
/// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
/// will funnel output to Android logcat.
#[cfg(feature = "gecko_debug")]
macro_rules! println_stderr {
($($e:expr),+) => {
{
let mut s = nsCString::new();
write!(s, $($e),+).unwrap();
s.write_char('\n').unwrap();
unsafe { bindings::Gecko_PrintfStderr(&s); }
}
}
}
#[cfg(feature = "gecko_debug")]
fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
println_stderr!(" Properties:");
for p in properties.iter() {
let mut v = String::new();
cv.get_longhand_property_value(p, &mut CssWriter::new(&mut v))
.unwrap();
println_stderr!(" {:?}: {}", p, v);
}
println_stderr!(" Rules:");
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
for rn in cv.rules().self_and_ancestors() {
if rn.importance().important() {
continue;
}
if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
println_stderr!(" [DeclarationBlock: {:?}]", d);
}
if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
let mut s = nsString::new();
r.read_with(&guard).to_css(&guard, &mut s).unwrap();
println_stderr!(" {}", s);
}
}
}
#[cfg(feature = "gecko_debug")]
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
a: &ComputedValues,
b: &ComputedValues,
) -> bool {
let mut differing_properties = a.differing_properties(b);
// Ignore any difference in -x-lang, which we can't override in the
// rules in minimal-xul.css, but which makes no difference for the
// anonymous content subtrees we cache style for.
differing_properties.remove(LonghandId::XLang);
// Ignore any difference in pref-controlled, inherited properties. These
// properties may or may not be set by the 'all' declaration in the
// minimal-xul.css rule, depending on whether the pref was enabled at the
// time the UA sheets were parsed.
//
// If you add a new pref-controlled, inherited property, it must be defined
// with `has_effect_on_gecko_scrollbars=False` to declare that
// different values of this property on a <scrollbar> element or its
// descendant scrollbar part elements should have no effect on their
// rendering and behavior.
//
// If you do need a pref-controlled, inherited property to have an effect
// on these elements, then you will need to add some checks to the
// nsIAnonymousContentCreator::CreateAnonymousContent implementations of
// ScrollFrameHelper and nsScrollbarFrame to clear the AnonymousContentKey
// if a non-initial value is used.
differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
if !differing_properties.is_empty() {
println_stderr!("Actual style:");
dump_properties_and_rules(a, &differing_properties);
println_stderr!("Expected style:");
dump_properties_and_rules(b, &differing_properties);
}
differing_properties.is_empty()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet {
let data = Box::new(PerDocumentStyleData::new(doc));
// Do this here rather than in Servo_Initialize since we need a document to
// get the default computed values from.
style::gecko_properties::assert_initial_values_match(&data);
Box::into_raw(data) as *mut RawServoStyleSet
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet) {
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
data.stylist.device_mut().rebuild_cached_data();
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut RawServoStyleSet) {
PerDocumentStyleData::drop_ffi(data);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &RawServoStyleSet) {
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let quirks_mode = data.stylist.device().document().mCompatMode;
data.stylist.set_quirks_mode(quirks_mode.into());
}
fn parse_property_into(
declarations: &mut SourcePropertyDeclaration,
property_id: PropertyId,
value: &nsACString,
origin: Origin,
url_data: &UrlExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: QuirksMode,
rule_type: CssRuleType,
reporter: Option<&dyn ParseErrorReporter>,
) -> Result<(), ()> {
let value = unsafe { value.as_str_unchecked() };
let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
if let Some(non_custom) = property_id.non_custom_id() {
if !non_custom.allowed_in_rule(rule_type) {
return Err(());
}
}
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
parse_one_declaration_into(
declarations,
property_id,
value,
origin,
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
url_data,
reporter,
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
parsing_mode,
quirks_mode,
rule_type,
)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ParseProperty(
property: nsCSSPropertyID,
value: &nsACString,
data: *mut URLExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
) -> Strong<RawServoDeclarationBlock> {
let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
let mut declarations = SourcePropertyDeclaration::new();
let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
let data = UrlExtraData::from_ptr_ref(&data);
let result = parse_property_into(
&mut declarations,
id,
value,
Origin::Author,
data,
parsing_mode,
quirks_mode.into(),
to_rule_type(rule_type),
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
);
match result {
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
Ok(()) => {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let mut block = PropertyDeclarationBlock::new();
block.extend(declarations.drain(), Importance::Normal);
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
},
Err(_) => Strong::null(),
}
}
#[no_mangle]
pub extern "C" fn Servo_ParseEasing(
easing: &nsAString,
output: &mut nsTimingFunction,
) -> bool {
use style::properties::longhands::transition_timing_function;
let context = ParserContext::new(
Origin::Author,
unsafe { dummy_url_data() },
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let easing = easing.to_string();
let mut input = ParserInput::new(&easing);
let mut parser = Parser::new(&mut input);
let result =
parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
match result {
Ok(parsed_easing) => {
// We store as computed value in nsTimingFunction.
(*output).mTiming = parsed_easing.to_computed_value_without_context();
true
},
Err(_) => false,
}
}
#[no_mangle]
pub extern "C" fn Servo_SerializeEasing(easing: &nsTimingFunction, output: &mut nsAString) {
easing.mTiming.to_css(&mut CssWriter::new(output)).unwrap();
}
#[no_mangle]
pub extern "C" fn Servo_GetProperties_Overriding_Animation(
element: &RawGeckoElement,
list: &nsTArray<nsCSSPropertyID>,
set: &mut structs::nsCSSPropertyIDSet,
) {
let element = GeckoElement(element);
let element_data = match element.borrow_data() {
Some(data) => data,
None => return,
};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let guards = StylesheetGuards::same(&guard);
let (overridden, custom) = element_data
.styles
.primary()
.rules()
.get_properties_overriding_animations(&guards);
for p in list.iter() {
match PropertyId::from_nscsspropertyid(*p) {
Ok(property) => {
if let PropertyId::Longhand(id) = property {
if overridden.contains(id) {
unsafe { Gecko_AddPropertyToSet(set, *p) };
}
}
},
Err(_) => {
if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
unsafe { Gecko_AddPropertyToSet(set, *p) };
}
},
}
}
}
#[no_mangle]
pub extern "C" fn Servo_MatrixTransform_Operate(
matrix_operator: MatrixTransformOperator,
from: *const structs::Matrix4x4Components,
to: *const structs::Matrix4x4Components,
progress: f64,
output: *mut structs::Matrix4x4Components,
) {
use self::MatrixTransformOperator::{Accumulate, Interpolate};
use style::values::computed::transform::Matrix3D;
let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
let result = match matrix_operator {
Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
Accumulate => from.animate(
&to,
Procedure::Accumulate {
count: progress as u64,
},
),
};
let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
servo: Merge #18591 - stylo: do not handle the fallback discrete animation inside the Animate trait (from chenpighead:stylo-singular-matrix-animation); r=BorisChiou At present, we do the fallback discrete animation for non-invertible matrices in ComputedMatrix.animate(). However, according to the spec, we should fallback to discrete animation for cases like: 1. animation between transform with single non-invertible matrix 2. animation between transform with matched transform functions that have at least one non-invertible matrix 2. animation between transform with mismatched transform functions that have at least one non-invertible matrix. The current implementation only handles the first case. Moreover, we already have fallback discrete animation procedures in CSS Animation and Web Animation, so we should be able to not doing any fallback inside the Animate trait. In this patch, we let the animation between non-invertible matrices to return Err(). So, we can propagate the Err() to the callers, and let the fallback discrete animation procedure stay at the Servo_MatrixTransform_Operate, which is ouside the Animate trait. Gecko bug: [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) - [X] There are wpt tests for these changes, and thet will be landed in [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) Source-Repo: https://github.com/servo/servo Source-Revision: ce7cee75e4c0c8357b489be42589d96348870627 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 830ee041c599c8dee799d36732e16f7e8b2fcd34
2017-09-21 11:16:58 +03:00
if let Ok(result) = result {
*output = result.into();
servo: Merge #18591 - stylo: do not handle the fallback discrete animation inside the Animate trait (from chenpighead:stylo-singular-matrix-animation); r=BorisChiou At present, we do the fallback discrete animation for non-invertible matrices in ComputedMatrix.animate(). However, according to the spec, we should fallback to discrete animation for cases like: 1. animation between transform with single non-invertible matrix 2. animation between transform with matched transform functions that have at least one non-invertible matrix 2. animation between transform with mismatched transform functions that have at least one non-invertible matrix. The current implementation only handles the first case. Moreover, we already have fallback discrete animation procedures in CSS Animation and Web Animation, so we should be able to not doing any fallback inside the Animate trait. In this patch, we let the animation between non-invertible matrices to return Err(). So, we can propagate the Err() to the callers, and let the fallback discrete animation procedure stay at the Servo_MatrixTransform_Operate, which is ouside the Animate trait. Gecko bug: [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) --- - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) - [X] There are wpt tests for these changes, and thet will be landed in [Bug 1394284](https://bugzilla.mozilla.org/show_bug.cgi?id=1394284) Source-Repo: https://github.com/servo/servo Source-Revision: ce7cee75e4c0c8357b489be42589d96348870627 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 830ee041c599c8dee799d36732e16f7e8b2fcd34
2017-09-21 11:16:58 +03:00
} else if progress < 0.5 {
*output = from.clone().into();
} else {
*output = to.clone().into();
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ParseStyleAttribute(
data: &nsACString,
raw_extra_data: *mut URLExtraData,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
) -> Strong<RawServoDeclarationBlock> {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let value = data.as_str_unchecked();
let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
value,
url_data,
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
quirks_mode.into(),
to_rule_type(rule_type),
)))
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<RawServoDeclarationBlock> {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(
global_style_data
.shared_lock
.wrap(PropertyDeclarationBlock::new()),
)
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Clone(
declarations: &RawServoDeclarationBlock,
) -> Strong<RawServoDeclarationBlock> {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
Arc::new(
global_style_data
.shared_lock
.wrap(declarations.read_with(&guard).clone()),
)
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Equals(
a: &RawServoDeclarationBlock,
b: &RawServoDeclarationBlock,
) -> bool {
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
*Locked::<PropertyDeclarationBlock>::as_arc(&a)
.read_with(&guard)
.declarations() ==
*Locked::<PropertyDeclarationBlock>::as_arc(&b)
.read_with(&guard)
.declarations()
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetCssText(
declarations: &RawServoDeclarationBlock,
result: &mut nsAString,
) {
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.to_css(result).unwrap()
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
declarations: &RawServoDeclarationBlock,
property_id: nsCSSPropertyID,
buffer: &mut nsAString,
computed_values: Option<&ComputedValues>,
custom_properties: Option<&RawServoDeclarationBlock>,
raw_data: &RawServoStyleSet,
) {
let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
let custom_properties =
Locked::<PropertyDeclarationBlock>::arc_from_borrowed(&custom_properties);
let custom_properties = custom_properties.map(|block| block.read_with(&guard));
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let rv = decls.single_value_to_css(
&property_id,
buffer,
computed_values,
custom_properties,
&data.stylist.device(),
);
debug_assert!(rv.is_ok());
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
declarations: &RawServoDeclarationBlock,
buffer: &mut nsAString,
) {
use style::properties::shorthands::font;
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
Ok(l) => l,
Err(()) => {
warn!("Unexpected property!");
return;
},
};
let rv = longhands.to_css(&mut CssWriter::new(buffer));
debug_assert!(rv.is_ok());
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &RawServoDeclarationBlock) -> u32 {
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.declarations().len() as u32
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
declarations: &RawServoDeclarationBlock,
index: u32,
result: &mut nsACString,
) -> bool {
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
if let Some(decl) = decls.declarations().get(index as usize) {
result.assign(&decl.id().name());
true
} else {
false
}
})
}
macro_rules! get_property_id_from_property {
($property: ident, $ret: expr) => {{
let property = $property.as_str_unchecked();
match PropertyId::parse_enabled_for_all_content(property) {
Ok(property_id) => property_id,
Err(_) => return $ret,
}
}};
}
unsafe fn get_property_value(
declarations: &RawServoDeclarationBlock,
property_id: PropertyId,
value: &mut nsAString,
) {
// This callsite is hot enough that the lock acquisition shows up in profiles.
// Using an unchecked read here improves our performance by ~10% on the
// microbenchmark in bug 1355599.
read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
decls.property_value_to_css(&property_id, value).unwrap();
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
declarations: &RawServoDeclarationBlock,
property: &nsACString,
value: &mut nsAString,
) {
get_property_value(
declarations,
get_property_id_from_property!(property, ()),
value,
)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: &mut nsAString,
) {
get_property_value(
declarations,
get_property_id_from_nscsspropertyid!(property, ()),
value,
)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
declarations: &RawServoDeclarationBlock,
property: &nsACString,
) -> bool {
let property_id = get_property_id_from_property!(property, false);
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.property_priority(&property_id).important()
})
}
#[inline(always)]
fn set_property_to_declarations(
block: &RawServoDeclarationBlock,
parsed_declarations: &mut SourcePropertyDeclaration,
before_change_closure: DeclarationBlockMutationClosure,
importance: Importance,
) -> bool {
let mut updates = Default::default();
let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
});
if !will_change {
return false;
}
before_change_closure.invoke();
write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
decls.update(parsed_declarations.drain(), importance, &mut updates)
});
true
}
fn set_property(
declarations: &RawServoDeclarationBlock,
property_id: PropertyId,
value: &nsACString,
is_important: bool,
data: &UrlExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: QuirksMode,
loader: *mut Loader,
rule_type: CssRuleType,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
let mut source_declarations = SourcePropertyDeclaration::new();
let reporter = ErrorReporter::new(ptr::null_mut(), loader, data.ptr());
let result = parse_property_into(
&mut source_declarations,
property_id,
value,
Origin::Author,
data,
parsing_mode,
quirks_mode,
rule_type,
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
);
if result.is_err() {
return false;
}
let importance = if is_important {
Importance::Important
} else {
Importance::Normal
};
set_property_to_declarations(
declarations,
&mut source_declarations,
before_change_closure,
importance,
)
}
#[inline]
fn to_rule_type(ty: u16) -> CssRuleType {
use num_traits::FromPrimitive;
CssRuleType::from_u16(ty).unwrap_or(CssRuleType::Style)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
declarations: &RawServoDeclarationBlock,
property: &nsACString,
value: &nsACString,
is_important: bool,
data: *mut URLExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
declarations,
get_property_id_from_property!(property, false),
value,
is_important,
UrlExtraData::from_ptr_ref(&data),
parsing_mode,
quirks_mode.into(),
loader,
to_rule_type(rule_type),
before_change_closure,
)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
declarations: &RawServoDeclarationBlock,
animation_value: &RawServoAnimationValue,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
let mut source_declarations =
SourcePropertyDeclaration::with_one(AnimationValue::as_arc(&animation_value).uncompute());
set_property_to_declarations(
declarations,
&mut source_declarations,
before_change_closure,
Importance::Normal,
)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: &nsACString,
is_important: bool,
data: *mut URLExtraData,
parsing_mode: structs::ParsingMode,
quirks_mode: nsCompatibility,
loader: *mut Loader,
rule_type: u16,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
set_property(
declarations,
get_property_id_from_nscsspropertyid!(property, false),
value,
is_important,
UrlExtraData::from_ptr_ref(&data),
parsing_mode,
quirks_mode.into(),
loader,
to_rule_type(rule_type),
before_change_closure,
)
}
fn remove_property(
declarations: &RawServoDeclarationBlock,
property_id: PropertyId,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.first_declaration_to_remove(&property_id)
});
let first_declaration = match first_declaration {
Some(i) => i,
None => return false,
};
before_change_closure.invoke();
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.remove_property(&property_id, first_declaration)
});
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
declarations: &RawServoDeclarationBlock,
property: &nsACString,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
remove_property(
declarations,
get_property_id_from_property!(property, false),
before_change_closure,
)
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
before_change_closure: DeclarationBlockMutationClosure,
) -> bool {
remove_property(
declarations,
get_property_id_from_nscsspropertyid!(property, false),
before_change_closure,
)
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_Create() -> Strong<RawServoMediaList> {
let global_style_data = &*GLOBAL_STYLE_DATA;
Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_DeepClone(list: &RawServoMediaList) -> Strong<RawServoMediaList> {
let global_style_data = &*GLOBAL_STYLE_DATA;
read_locked_arc(list, |list: &MediaList| {
Arc::new(global_style_data.shared_lock.wrap(list.clone())).into_strong()
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_Matches(
list: &RawServoMediaList,
raw_data: &RawServoStyleSet,
) -> bool {
let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
read_locked_arc(list, |list: &MediaList| {
list.evaluate(
per_doc_data.stylist.device(),
per_doc_data.stylist.quirks_mode(),
)
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
) -> bool {
let property_id = get_property_id_from_nscsspropertyid!(property, false);
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.has_css_wide_keyword(&property_id)
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetText(list: &RawServoMediaList, result: &mut nsAString) {
read_locked_arc(list, |list: &MediaList| {
list.to_css(&mut CssWriter::new(result)).unwrap();
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_MediaList_SetText(
list: &RawServoMediaList,
text: &nsACString,
caller_type: CallerType,
) {
let text = text.as_str_unchecked();
let mut input = ParserInput::new(&text);
let mut parser = Parser::new(&mut input);
let url_data = dummy_url_data();
// TODO(emilio): If the need for `CallerType` appears in more places,
// consider adding an explicit member in `ParserContext` instead of doing
// this (or adding a dummy "chrome://" url data).
//
// For media query parsing it's effectively the same, so for now...
let origin = match caller_type {
CallerType::System => Origin::UserAgent,
CallerType::NonSystem => Origin::Author,
};
let context = ParserContext::new(
origin,
url_data,
Some(CssRuleType::Media),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
// TODO(emilio): Looks like error reporting could be useful here?
None,
None,
);
write_locked_arc(list, |list: &mut MediaList| {
*list = MediaList::parse(&context, &mut parser);
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetLength(list: &RawServoMediaList) -> u32 {
read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_GetMediumAt(
list: &RawServoMediaList,
index: u32,
result: &mut nsAString,
) -> bool {
read_locked_arc(list, |list: &MediaList| {
let media_query = match list.media_queries.get(index as usize) {
Some(mq) => mq,
None => return false,
};
media_query.to_css(&mut CssWriter::new(result)).unwrap();
true
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_AppendMedium(list: &RawServoMediaList, new_medium: &nsACString) {
let new_medium = unsafe { new_medium.as_str_unchecked() };
let url_data = unsafe { dummy_url_data() };
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Media),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
write_locked_arc(list, |list: &mut MediaList| {
list.append_medium(&context, new_medium);
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_DeleteMedium(
list: &RawServoMediaList,
old_medium: &nsACString,
) -> bool {
let old_medium = unsafe { old_medium.as_str_unchecked() };
let url_data = unsafe { dummy_url_data() };
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Media),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
write_locked_arc(list, |list: &mut MediaList| {
list.delete_medium(&context, old_medium)
})
}
#[no_mangle]
pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
list: &RawServoMediaList,
) -> usize {
use malloc_size_of::MallocSizeOf;
use malloc_size_of::MallocUnconditionalShallowSizeOf;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
None,
);
Locked::<MediaList>::as_arc(&list).with_arc(|list| {
let mut n = 0;
n += list.unconditional_shallow_size_of(&mut ops);
n += list.read_with(&guard).size_of(&mut ops);
n
})
}
macro_rules! get_longhand_from_id {
($id:expr) => {
match PropertyId::from_nscsspropertyid($id) {
Ok(PropertyId::Longhand(long)) => long,
_ => {
panic!("stylo: unknown presentation property with id");
},
}
};
}
macro_rules! match_wrap_declared {
($longhand:ident, $($property:ident => $inner:expr,)*) => (
match $longhand {
$(
LonghandId::$property => PropertyDeclaration::$property($inner),
)*
_ => {
panic!("stylo: Don't know how to handle presentation property");
}
}
)
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
) -> bool {
read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
decls.contains(get_longhand_from_id!(property))
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: *mut nsAtom,
) {
use style::properties::longhands::_x_lang::computed_value::T as Lang;
use style::properties::PropertyDeclaration;
let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long,
XLang => Lang(Atom::from_raw(value)),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
#[allow(unreachable_code)]
pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: i32,
) {
use num_traits::FromPrimitive;
use style::properties::longhands;
use style::properties::PropertyDeclaration;
use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
use style::values::generics::font::FontStyle;
use style::values::specified::{BorderStyle, Clear, Display, Float, TextAlign};
fn get_from_computed<T>(value: u32) -> T
where
T: ToComputedValue,
T::ComputedValue: FromPrimitive,
{
T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
}
let long = get_longhand_from_id!(property);
let value = value as u32;
let prop = match_wrap_declared! { long,
MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
Display => get_from_computed::<Display>(value),
Float => get_from_computed::<Float>(value),
Clear => get_from_computed::<Clear>(value),
VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
TextAlign => get_from_computed::<TextAlign>(value),
TextEmphasisPosition => longhands::text_emphasis_position::SpecifiedValue::from_gecko_keyword(value),
FontSize => {
// We rely on Gecko passing in font-size values (0...7) here.
longhands::font_size::SpecifiedValue::from_html_size(value as u8)
},
FontStyle => {
let val = if value == structs::NS_FONT_STYLE_ITALIC {
FontStyle::Italic
} else {
debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
FontStyle::Normal
};
ToComputedValue::from_computed_value(&val)
},
FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
MathStyle => longhands::math_style::SpecifiedValue::from_gecko_keyword(value),
MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value),
BorderTopStyle => get_from_computed::<BorderStyle>(value),
BorderRightStyle => get_from_computed::<BorderStyle>(value),
BorderBottomStyle => get_from_computed::<BorderStyle>(value),
BorderLeftStyle => get_from_computed::<BorderStyle>(value),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: i32,
) {
use style::properties::PropertyDeclaration;
use style::values::specified::Integer;
let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long,
XSpan => Integer::new(value),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetMathDepthValue(
declarations: &RawServoDeclarationBlock,
value: i32,
is_relative: bool,
) {
use style::properties::longhands::math_depth::SpecifiedValue as MathDepth;
use style::properties::PropertyDeclaration;
let integer_value = style::values::specified::Integer::new(value);
let prop = PropertyDeclaration::MathDepth(if is_relative {
MathDepth::Add(integer_value)
} else {
MathDepth::Absolute(integer_value)
});
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
declarations: &RawServoDeclarationBlock,
counter_value: i32,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::counters::{CounterPair, CounterSetOrReset};
let prop = PropertyDeclaration::CounterReset(CounterSetOrReset::new(vec![CounterPair {
name: CustomIdent(atom!("list-item")),
value: style::values::specified::Integer::new(counter_value),
}]));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
declarations: &RawServoDeclarationBlock,
counter_value: i32,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::counters::{CounterPair, CounterSetOrReset};
let prop = PropertyDeclaration::CounterSet(CounterSetOrReset::new(vec![CounterPair {
name: CustomIdent(atom!("list-item")),
value: style::values::specified::Integer::new(counter_value),
}]));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: f32,
) {
use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
use style::properties::PropertyDeclaration;
use style::values::generics::length::LengthPercentageOrAuto;
use style::values::generics::length::Size;
use style::values::generics::NonNegative;
use style::values::specified::length::LengthPercentage;
use style::values::specified::length::NonNegativeLengthPercentage;
use style::values::specified::length::{NoCalcLength, NonNegativeLength};
use style::values::specified::{BorderCornerRadius, BorderSideWidth};
let long = get_longhand_from_id!(property);
let nocalc = NoCalcLength::from_px(value);
let lp = LengthPercentage::Length(nocalc);
let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
let prop = match_wrap_declared! { long,
Height => Size::LengthPercentage(NonNegative(lp)),
Width => Size::LengthPercentage(NonNegative(lp)),
BorderTopWidth => BorderSideWidth::Length(nocalc.into()),
BorderRightWidth => BorderSideWidth::Length(nocalc.into()),
BorderBottomWidth => BorderSideWidth::Length(nocalc.into()),
BorderLeftWidth => BorderSideWidth::Length(nocalc.into()),
MarginTop => lp_or_auto,
MarginRight => lp_or_auto,
MarginBottom => lp_or_auto,
MarginLeft => lp_or_auto,
PaddingTop => NonNegative(lp),
PaddingRight => NonNegative(lp),
PaddingBottom => NonNegative(lp),
PaddingLeft => NonNegative(lp),
BorderSpacing => {
let v = NonNegativeLength::from(nocalc);
Box::new(BorderSpacing::new(v.clone(), v))
},
BorderTopLeftRadius => {
let length = NonNegativeLengthPercentage::from(nocalc);
Box::new(BorderCornerRadius::new(length.clone(), length))
},
BorderTopRightRadius => {
let length = NonNegativeLengthPercentage::from(nocalc);
Box::new(BorderCornerRadius::new(length.clone(), length))
},
BorderBottomLeftRadius => {
let length = NonNegativeLengthPercentage::from(nocalc);
Box::new(BorderCornerRadius::new(length.clone(), length))
},
BorderBottomRightRadius => {
let length = NonNegativeLengthPercentage::from(nocalc);
Box::new(BorderCornerRadius::new(length.clone(), length))
},
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: f32,
unit: structs::nsCSSUnit,
) {
use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
use style::properties::PropertyDeclaration;
use style::values::generics::length::{LengthPercentageOrAuto, Size};
use style::values::generics::NonNegative;
use style::values::specified::length::{AbsoluteLength, FontRelativeLength};
use style::values::specified::length::{LengthPercentage, NoCalcLength};
use style::values::specified::FontSize;
let long = get_longhand_from_id!(property);
let nocalc = match unit {
structs::nsCSSUnit::eCSSUnit_EM => {
NoCalcLength::FontRelative(FontRelativeLength::Em(value))
},
structs::nsCSSUnit::eCSSUnit_XHeight => {
NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
},
structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
structs::nsCSSUnit::eCSSUnit_Centimeter => {
NoCalcLength::Absolute(AbsoluteLength::Cm(value))
},
structs::nsCSSUnit::eCSSUnit_Millimeter => {
NoCalcLength::Absolute(AbsoluteLength::Mm(value))
},
structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
_ => unreachable!("Unknown unit passed to SetLengthValue"),
};
let prop = match_wrap_declared! { long,
Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
X => LengthPercentage::Length(nocalc),
Y => LengthPercentage::Length(nocalc),
Cx => LengthPercentage::Length(nocalc),
Cy => LengthPercentage::Length(nocalc),
R => NonNegative(LengthPercentage::Length(nocalc)),
Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
MozScriptMinSize => MozScriptMinSize(nocalc),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetNumberValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: f32,
) {
use style::properties::longhands::_moz_script_size_multiplier::SpecifiedValue as MozScriptSizeMultiplier;
use style::properties::PropertyDeclaration;
let long = get_longhand_from_id!(property);
let prop = match_wrap_declared! { long,
MozScriptSizeMultiplier => MozScriptSizeMultiplier(value),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: f32,
) {
use style::properties::PropertyDeclaration;
use style::values::computed::Percentage;
use style::values::generics::length::{LengthPercentageOrAuto, Size};
use style::values::generics::NonNegative;
use style::values::specified::length::LengthPercentage;
use style::values::specified::FontSize;
let long = get_longhand_from_id!(property);
let pc = Percentage(value);
let lp = LengthPercentage::Percentage(pc);
let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
let prop = match_wrap_declared! { long,
Height => Size::LengthPercentage(NonNegative(lp)),
Width => Size::LengthPercentage(NonNegative(lp)),
X => lp,
Y => lp,
Cx => lp,
Cy => lp,
R => NonNegative(lp),
Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
MarginTop => lp_or_auto,
MarginRight => lp_or_auto,
MarginBottom => lp_or_auto,
MarginLeft => lp_or_auto,
FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::length::{LengthPercentageOrAuto, Size};
let long = get_longhand_from_id!(property);
let auto = LengthPercentageOrAuto::Auto;
let prop = match_wrap_declared! { long,
Height => Size::auto(),
Width => Size::auto(),
MarginTop => auto,
MarginRight => auto,
MarginBottom => auto,
MarginLeft => auto,
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
) {
use style::properties::PropertyDeclaration;
use style::values::specified::Color;
let long = get_longhand_from_id!(property);
let cc = Color::currentcolor();
let prop = match_wrap_declared! { long,
BorderTopColor => cc,
BorderRightColor => cc,
BorderBottomColor => cc,
BorderLeftColor => cc,
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
declarations: &RawServoDeclarationBlock,
property: nsCSSPropertyID,
value: structs::nscolor,
) {
use style::gecko::values::convert_nscolor_to_rgba;
use style::properties::longhands;
use style::properties::PropertyDeclaration;
use style::values::specified::Color;
let long = get_longhand_from_id!(property);
let rgba = convert_nscolor_to_rgba(value);
let color = Color::rgba(rgba);
let prop = match_wrap_declared! { long,
BorderTopColor => color,
BorderRightColor => color,
BorderBottomColor => color,
BorderLeftColor => color,
Color => longhands::color::SpecifiedValue(color),
BackgroundColor => color,
};
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(prop, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(
declarations: &RawServoDeclarationBlock,
value: &nsAString,
) {
use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
use style::properties::PropertyDeclaration;
let string = value.to_string();
let mut input = ParserInput::new(&string);
let mut parser = Parser::new(&mut input);
let result = FontFamily::parse_specified(&mut parser);
if let Ok(family) = result {
if parser.is_exhausted() {
let decl = PropertyDeclaration::FontFamily(family);
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);
})
}
}
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
declarations: &RawServoDeclarationBlock,
value: &nsAString,
raw_extra_data: *mut URLExtraData,
) {
use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
use style::properties::PropertyDeclaration;
2019-06-03 15:22:30 +03:00
use style::stylesheets::CorsMode;
use style::values::generics::image::Image;
use style::values::specified::url::SpecifiedImageUrl;
let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
let string = value.to_string();
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
2019-06-03 15:22:30 +03:00
let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Image::Url(url)].into()));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);
});
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
declarations: &RawServoDeclarationBlock,
) {
use style::properties::PropertyDeclaration;
use style::values::specified::text::TextDecorationLine;
let decoration = TextDecorationLine::COLOR_OVERRIDE;
let decl = PropertyDeclaration::TextDecorationLine(decoration);
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
declarations: &RawServoDeclarationBlock,
width: f32,
height: f32,
) {
use style::properties::PropertyDeclaration;
use style::values::generics::position::AspectRatio;
let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);
})
}
#[no_mangle]
pub extern "C" fn Servo_CSSSupports2(property: &nsACString, value: &nsACString) -> bool {
let id = unsafe { get_property_id_from_property!(property, false) };
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
let mut declarations = SourcePropertyDeclaration::new();
parse_property_into(
&mut declarations,
id,
value,
Origin::Author,
unsafe { dummy_url_data() },
servo: Merge #16954 - Avoid returning / passing around a huge ParsedDeclaration type (from servo:arrayvec); r=emilio This enum type used to contain the result of parsing one CSS source declaration (`name: value;`) and expanding shorthands. Enum types are as big as the biggest of their variant (plus discriminant), which was quite big because some shorthands expand to many longhand properties. This type was returned through many functions and methods, wrapped and rewrapped in `Result` with different error types. This presumably caused significant `memmove` traffic. Instead, we now allocate an `ArrayVec` on the stack and pass `&mut` references to it for various functions to push into it. This type is also very big, but we never move it. We still use an intermediate data structure because we sometimes decide after shorthand expansion that a declaration is invalid after all and that we’re gonna drop it. Only later do we push to a `PropertyDeclarationBlock`, with an entire `ArrayVec` or nothing. In future work we can try to avoid a large stack-allocated array, and instead writing directly to the heap allocation of the `Vec` inside `PropertyDeclarationBlock`. However this is tricky: we need to preserve this "all or nothing" aspect of parsing one source declaration, and at the same time we want to make it as little error-prone as possible for the various call sites. `PropertyDeclarationBlock` curently does property deduplication incrementally: as each `PropertyDeclaration` is pushed, we check if an existing declaration of the same property exists and if so overwrite it. To get rid of the stack allocated array we’d need to somehow deduplicate separately after pushing multiple `PropertyDeclaration`. Source-Repo: https://github.com/servo/servo Source-Revision: 60682cf81fe19a82c73dd98ba4c1eebc1dbbfcac --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : bf9916ad96bb4c2eedcb7a52110170644c269133
2017-05-20 02:37:14 +03:00
structs::ParsingMode_Default,
QuirksMode::NoQuirks,
CssRuleType::Style,
None,
)
.is_ok()
}
servo: Merge #12469 - style: Rewrite the restyle hints code to allow different kinds of element snapshots (from emilio:stylo); r=bholley <!-- 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 <!-- Either: --> - [x] These changes do not require tests because refactoring. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> This is a rewrite for how style interfaces with its consumers in order to allow different representations for an element snapshot. This also changes the requirements of an element snapshot, requiring them to only implement MatchAttr, instead of MatchAttrGeneric. This is important for stylo since implementing MatchAttrGeneric is way more difficult for us given the atom limitations. This also allows for more performant implementations in the Gecko side of things. I don't want to get this merged just yet, mainly because the stylo part is not implemented, but I'd like early feedback from @bholley and/or @heycam: How do you see this approach? I don't think we'll have much problem to implement MatchAttr for our element snapshots, but... worth checking. r? @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 1e0321f7dde5f33f7d26bbd4f088622fa3660477
2016-07-22 00:54:34 +03:00
#[no_mangle]
pub extern "C" fn Servo_CSSSupports(
cond: &nsACString,
ua_origin: bool,
chrome_sheet: bool,
quirks: bool,
) -> bool {
let condition = unsafe { cond.as_str_unchecked() };
let mut input = ParserInput::new(&condition);
let mut input = Parser::new(&mut input);
let cond = match input.parse_entirely(parse_condition_or_declaration) {
Ok(c) => c,
Err(..) => return false,
};
let origin = if ua_origin {
Origin::UserAgent
} else {
Origin::Author
};
let url_data = unsafe {
UrlExtraData::from_ptr_ref(if chrome_sheet {
&DUMMY_CHROME_URL_DATA
} else {
&DUMMY_URL_DATA
})
};
let quirks_mode = if quirks {
QuirksMode::Quirks
} else {
QuirksMode::NoQuirks
};
// NOTE(emilio): The supports API is not associated to any stylesheet,
// so the fact that there is no namespace map here is fine.
let context = ParserContext::new(
origin,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
quirks_mode,
None,
None,
);
let namespaces = Default::default();
cond.eval(&context, &namespaces)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_NoteExplicitHints(
element: &RawGeckoElement,
restyle_hint: RestyleHint,
change_hint: nsChangeHint,
) {
GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
}
#[no_mangle]
pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: *mut bool) -> u32 {
let was_restyled = unsafe { was_restyled.as_mut().unwrap() };
let element = GeckoElement(element);
let damage = match element.mutate_data() {
Some(mut data) => {
*was_restyled = data.is_restyle();
let damage = data.damage;
data.clear_restyle_state();
damage
},
None => {
warn!("Trying to get change hint from unstyled element");
*was_restyled = false;
GeckoRestyleDamage::empty()
},
};
debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
// We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
// work as return values with the Linux 32-bit ABI at the moment because
// they wrap the value in a struct, so for now just unwrap it.
damage.as_change_hint().0
}
#[no_mangle]
pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
let element = GeckoElement(element);
debug!("Servo_ResolveStyle: {:?}", element);
let data = element
.borrow_data()
.expect("Resolving style on unstyled element");
servo: Merge #14436 - Make restyle tracking more granular (from bholley:granular_restyle); r=emilio The primary idea of this patch is to ditch the rigid enum of Previous/Current styles, and replace it with a series of indicators for the various types of work that needs to be performed (expanding snapshots, rematching, recascading, and damage processing). This loses us a little bit of sanity checking (since the up-to-date-ness of our style is no longer baked into the type system), but gives us a lot more flexibility that we'll need going forward (especially when we separate matching from cascading). We also eliminate get_styling_mode in favor of a method on the traversal. This patch does a few other things as ridealongs: * Temporarily eliminates the handling for transfering ownership of styles to the frame. We'll need this again at some point, but for now it's causing too much complexity for a half-implemented feature. * Ditches TRestyleDamage, which is no longer necessary post-crate-merge, and is a constant source of compilation failures from either needing to be imported or being unnecessarily imported (which varies between gecko and servo). * Expands Snapshots for the traversal root, which was missing before. * Fixes up the skip_root stuff to avoid visiting the skipped root. * Unifies parallel traversal and avoids spawning for a single work item. * Adds an explicit pre_traverse step do any pre-processing and determine whether we need to traverse at all. Source-Repo: https://github.com/servo/servo Source-Revision: b9a8ccd775c3192e3810a1730b1d0bc2b5c9dfb6
2016-12-10 04:01:05 +03:00
debug_assert!(
element.has_current_styles(&*data),
"Resolving style on {:?} without current styles: {:?}",
element,
data
);
data.styles.primary().clone().into()
}
servo: Merge #12469 - style: Rewrite the restyle hints code to allow different kinds of element snapshots (from emilio:stylo); r=bholley <!-- 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 <!-- Either: --> - [x] These changes do not require tests because refactoring. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> This is a rewrite for how style interfaces with its consumers in order to allow different representations for an element snapshot. This also changes the requirements of an element snapshot, requiring them to only implement MatchAttr, instead of MatchAttrGeneric. This is important for stylo since implementing MatchAttrGeneric is way more difficult for us given the atom limitations. This also allows for more performant implementations in the Gecko side of things. I don't want to get this merged just yet, mainly because the stylo part is not implemented, but I'd like early feedback from @bholley and/or @heycam: How do you see this approach? I don't think we'll have much problem to implement MatchAttr for our element snapshots, but... worth checking. r? @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 1e0321f7dde5f33f7d26bbd4f088622fa3660477
2016-07-22 00:54:34 +03:00
#[no_mangle]
pub extern "C" fn Servo_ResolveStyleLazily(
element: &RawGeckoElement,
pseudo_type: PseudoStyleType,
rule_inclusion: StyleRuleInclusion,
snapshots: *const ServoElementSnapshotTable,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
debug_assert!(!snapshots.is_null());
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let element = GeckoElement(element);
let doc_data = PerDocumentStyleData::from_ffi(raw_data);
let data = doc_data.borrow();
let rule_inclusion = RuleInclusion::from(rule_inclusion);
let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
match pseudo {
Some(ref pseudo) => {
get_pseudo_style(
&guard,
element,
pseudo,
rule_inclusion,
styles,
/* inherited_styles = */ None,
&*data,
is_probe,
/* matching_func = */ None,
)
},
None => Some(styles.primary().clone()),
}
};
let is_before_or_after = pseudo.as_ref().map_or(false, |p| p.is_before_or_after());
// In the common case we already have the style. Check that before setting
// up all the computation machinery.
//
// Also, only probe in the ::before or ::after case, since their styles may
// not be in the `ElementData`, given they may exist but not be applicable
// to generate an actual pseudo-element (like, having a `content: none`).
if rule_inclusion == RuleInclusion::All {
let styles = element.mutate_data().and_then(|d| {
if d.has_styles() {
finish(&d.styles, is_before_or_after)
} else {
None
}
});
if let Some(result) = styles {
return result.into();
}
}
// We don't have the style ready. Go ahead and compute it as necessary.
let shared = create_shared_context(
&global_style_data,
&guard,
&data,
TraversalFlags::empty(),
unsafe { &*snapshots },
);
let mut tlc = ThreadLocalStyleContext::new(&shared);
let mut context = StyleContext {
shared: &shared,
thread_local: &mut tlc,
};
let styles = resolve_style(&mut context, element, rule_inclusion, pseudo.as_ref());
finish(&styles, /* is_probe = */ false)
.expect("We're not probing, so we should always get a style back")
.into()
}
#[no_mangle]
pub extern "C" fn Servo_ReparentStyle(
style_to_reparent: &ComputedValues,
parent_style: &ComputedValues,
parent_style_ignoring_first_line: &ComputedValues,
layout_parent_style: &ComputedValues,
element: Option<&RawGeckoElement>,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let inputs = CascadeInputs::new_from_style(style_to_reparent);
let metrics = get_metrics_provider_for_product();
let pseudo = style_to_reparent.pseudo();
let element = element.map(GeckoElement);
doc_data
.stylist
.cascade_style_and_visited(
element,
pseudo.as_ref(),
inputs,
&StylesheetGuards::same(&guard),
Some(parent_style),
Some(parent_style_ignoring_first_line),
Some(layout_parent_style),
&metrics,
/* rule_cache = */ None,
&mut RuleCacheConditions::default(),
)
.into()
}
#[cfg(feature = "gecko_debug")]
fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
let p = property.mProperty;
let id = get_property_id_from_nscsspropertyid!(p, false);
id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
}
#[cfg(not(feature = "gecko_debug"))]
fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
false
}
fn create_context_for_animation<'a>(
per_doc_data: &'a PerDocumentStyleDataImpl,
font_metrics_provider: &'a dyn FontMetricsProvider,
style: &'a ComputedValues,
parent_style: Option<&'a ComputedValues>,
for_smil_animation: bool,
rule_cache_conditions: &'a mut RuleCacheConditions,
) -> Context<'a> {
Context {
builder: StyleBuilder::for_animation(per_doc_data.stylist.device(), style, parent_style),
font_metrics_provider,
cached_system_font: None,
in_media_query: false,
quirks_mode: per_doc_data.stylist.quirks_mode(),
for_smil_animation,
for_non_inherited_property: None,
rule_cache_conditions: RefCell::new(rule_cache_conditions),
}
}
struct PropertyAndIndex {
property: PropertyId,
index: usize,
}
struct PrioritizedPropertyIter<'a> {
properties: &'a [PropertyValuePair],
sorted_property_indices: Vec<PropertyAndIndex>,
curr: usize,
}
impl<'a> PrioritizedPropertyIter<'a> {
fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
use style::values::animated::compare_property_priority;
// If we fail to convert a nsCSSPropertyID into a PropertyId we
// shouldn't fail outright but instead by treating that property as the
// 'all' property we make it sort last.
let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
.iter()
.enumerate()
.map(|(index, pair)| {
let property = PropertyId::from_nscsspropertyid(pair.mProperty)
.unwrap_or(PropertyId::Shorthand(ShorthandId::All));
PropertyAndIndex { property, index }
})
.collect();
sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
PrioritizedPropertyIter {
properties,
sorted_property_indices,
curr: 0,
}
}
}
impl<'a> Iterator for PrioritizedPropertyIter<'a> {
type Item = &'a PropertyValuePair;
fn next(&mut self) -> Option<&'a PropertyValuePair> {
if self.curr >= self.sorted_property_indices.len() {
return None;
}
self.curr += 1;
Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
}
}
#[no_mangle]
pub extern "C" fn Servo_GetComputedKeyframeValues(
keyframes: &nsTArray<structs::Keyframe>,
element: &RawGeckoElement,
pseudo_type: PseudoStyleType,
style: &ComputedValues,
raw_data: &RawServoStyleSet,
computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
) {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let metrics = get_metrics_provider_for_product();
let element = GeckoElement(element);
let parent_element = element.inheritance_parent();
let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
let parent_style = parent_data
.as_ref()
.map(|d| d.styles.primary())
.map(|x| &**x);
let mut conditions = Default::default();
let mut context = create_context_for_animation(
&data,
&metrics,
&style,
parent_style,
/* for_smil_animation = */ false,
&mut conditions,
);
let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
let restriction = pseudo.and_then(|p| p.property_restriction());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let default_values = data.default_computed_values();
let mut raw_custom_properties_block; // To make the raw block alive in the scope.
for (index, keyframe) in keyframes.iter().enumerate() {
let mut custom_properties = None;
for property in keyframe.mPropertyValues.iter() {
// Find the block for custom properties first.
if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
raw_custom_properties_block =
unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
let guard =
Locked::<PropertyDeclarationBlock>::as_arc(&raw_custom_properties_block)
.read_with(&guard);
custom_properties = guard.cascade_custom_properties_with_context(&context);
// There should be one PropertyDeclarationBlock for custom properties.
break;
}
}
let ref mut animation_values = computed_keyframes[index];
let mut seen = LonghandIdSet::new();
let mut property_index = 0;
for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) {
if simulate_compute_values_failure(property) {
continue;
}
let mut maybe_append_animation_value =
|property: LonghandId, value: Option<AnimationValue>| {
debug_assert!(!property.is_logical());
debug_assert!(property.is_animatable());
// 'display' is only animatable from SMIL
if property == LonghandId::Display {
return;
}
// Skip restricted properties
if restriction.map_or(false, |r| !property.flags().contains(r)) {
return;
}
if seen.contains(property) {
return;
}
seen.insert(property);
// This is safe since we immediately write to the uninitialized values.
unsafe { animation_values.set_len((property_index + 1) as u32) };
animation_values[property_index].mProperty = property.to_nscsspropertyid();
match value {
Some(v) => {
animation_values[property_index]
.mValue
.mServo
.set_arc_leaky(Arc::new(v));
},
None => {
animation_values[property_index].mValue.mServo.mRawPtr =
ptr::null_mut();
},
}
property_index += 1;
};
if property.mServoDeclarationBlock.mRawPtr.is_null() {
let property = LonghandId::from_nscsspropertyid(property.mProperty);
if let Ok(prop) = property {
maybe_append_animation_value(prop, None);
}
continue;
}
let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read_with(&guard);
let iter = guard.to_animation_value_iter(
&mut context,
&default_values,
custom_properties.as_ref(),
);
for value in iter {
let id = value.id();
maybe_append_animation_value(id, Some(value));
}
}
}
}
#[no_mangle]
pub extern "C" fn Servo_GetAnimationValues(
declarations: &RawServoDeclarationBlock,
element: &RawGeckoElement,
style: &ComputedValues,
raw_data: &RawServoStyleSet,
animation_values: &mut nsTArray<structs::RefPtr<structs::RawServoAnimationValue>>,
) {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let metrics = get_metrics_provider_for_product();
let element = GeckoElement(element);
let parent_element = element.inheritance_parent();
let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
let parent_style = parent_data
.as_ref()
.map(|d| d.styles.primary())
.map(|x| &**x);
let mut conditions = Default::default();
let mut context = create_context_for_animation(
&data,
&metrics,
&style,
parent_style,
/* for_smil_animation = */ true,
&mut conditions,
);
let default_values = data.default_computed_values();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
let guard = declarations.read_with(&guard);
let iter = guard.to_animation_value_iter(
&mut context,
&default_values,
None, // SMIL has no extra custom properties.
);
for (index, anim) in iter.enumerate() {
unsafe { animation_values.set_len((index + 1) as u32) };
animation_values[index].set_arc_leaky(Arc::new(anim));
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetPropertyId(
value: &RawServoAnimationValue,
) -> nsCSSPropertyID {
let value = AnimationValue::as_arc(&value);
value.id().to_nscsspropertyid()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Compute(
element: &RawGeckoElement,
declarations: &RawServoDeclarationBlock,
style: &ComputedValues,
raw_data: &RawServoStyleSet,
) -> Strong<RawServoAnimationValue> {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let metrics = get_metrics_provider_for_product();
let element = GeckoElement(element);
let parent_element = element.inheritance_parent();
let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
let parent_style = parent_data
.as_ref()
.map(|d| d.styles.primary())
.map(|x| &**x);
let mut conditions = Default::default();
let mut context = create_context_for_animation(
&data,
&metrics,
style,
parent_style,
/* for_smil_animation = */ false,
&mut conditions,
);
let default_values = data.default_computed_values();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
// We only compute the first element in declarations.
match declarations
.read_with(&guard)
.declaration_importance_iter()
.next()
{
Some((decl, imp)) if imp == Importance::Normal => {
let animation = AnimationValue::from_declaration(
decl,
&mut context,
None, // No extra custom properties for devtools.
default_values,
);
animation.map_or(Strong::null(), |value| Arc::new(value).into_strong())
},
_ => Strong::null(),
}
}
#[no_mangle]
pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
if !cfg!(feature = "gecko_debug") {
panic!("Calling Servo_AssertTreeIsClean in release build");
}
let root = GeckoElement(root);
debug!("Servo_AssertTreeIsClean: ");
debug!("{:?}", ShowSubtreeData(root.as_node()));
fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
debug_assert!(
!el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
"{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
el,
el.has_dirty_descendants(),
el.has_animation_only_dirty_descendants()
);
for child in el.traversal_children() {
if let Some(child) = child.as_element() {
assert_subtree_is_clean(child);
}
}
}
servo: Merge #12469 - style: Rewrite the restyle hints code to allow different kinds of element snapshots (from emilio:stylo); r=bholley <!-- 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 <!-- Either: --> - [x] These changes do not require tests because refactoring. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> This is a rewrite for how style interfaces with its consumers in order to allow different representations for an element snapshot. This also changes the requirements of an element snapshot, requiring them to only implement MatchAttr, instead of MatchAttrGeneric. This is important for stylo since implementing MatchAttrGeneric is way more difficult for us given the atom limitations. This also allows for more performant implementations in the Gecko side of things. I don't want to get this merged just yet, mainly because the stylo part is not implemented, but I'd like early feedback from @bholley and/or @heycam: How do you see this approach? I don't think we'll have much problem to implement MatchAttr for our element snapshots, but... worth checking. r? @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 1e0321f7dde5f33f7d26bbd4f088622fa3660477
2016-07-22 00:54:34 +03:00
assert_subtree_is_clean(root);
servo: Merge #12469 - style: Rewrite the restyle hints code to allow different kinds of element snapshots (from emilio:stylo); r=bholley <!-- 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 <!-- Either: --> - [x] These changes do not require tests because refactoring. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> This is a rewrite for how style interfaces with its consumers in order to allow different representations for an element snapshot. This also changes the requirements of an element snapshot, requiring them to only implement MatchAttr, instead of MatchAttrGeneric. This is important for stylo since implementing MatchAttrGeneric is way more difficult for us given the atom limitations. This also allows for more performant implementations in the Gecko side of things. I don't want to get this merged just yet, mainly because the stylo part is not implemented, but I'd like early feedback from @bholley and/or @heycam: How do you see this approach? I don't think we'll have much problem to implement MatchAttr for our element snapshots, but... worth checking. r? @heycam Source-Repo: https://github.com/servo/servo Source-Revision: 1e0321f7dde5f33f7d26bbd4f088622fa3660477
2016-07-22 00:54:34 +03:00
}
#[no_mangle]
pub extern "C" fn Servo_IsWorkerThread() -> bool {
thread_state::get().is_worker()
}
enum Offset {
Zero,
One,
}
fn fill_in_missing_keyframe_values(
all_properties: &LonghandIdSet,
timing_function: &nsTimingFunction,
longhands_at_offset: &LonghandIdSet,
offset: Offset,
keyframes: &mut nsTArray<structs::Keyframe>,
) {
// Return early if all animated properties are already set.
if longhands_at_offset.contains_all(all_properties) {
return;
}
let keyframe = match offset {
Offset::Zero => unsafe { Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function) },
Offset::One => unsafe { Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function) },
};
// Append properties that have not been set at this offset.
for property in all_properties.iter() {
if !longhands_at_offset.contains(property) {
unsafe {
Gecko_AppendPropertyValuePair(
&mut *(*keyframe).mPropertyValues,
property.to_nscsspropertyid(),
);
}
}
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
raw_data: &RawServoStyleSet,
element: &RawGeckoElement,
style: &ComputedValues,
name: *mut nsAtom,
inherited_timing_function: &nsTimingFunction,
keyframes: &mut nsTArray<structs::Keyframe>,
) -> bool {
debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
servo: Merge #16014 - Per-process lock for CSSOM objects (from servo:style-ref); r=emilio <!-- Please describe your changes on the following line: --> Before this PR, every object reflected in CSSOM is in `Arc<RwLock<_>>` to enable safe (synchronized) mutable aliasing. Acquiring all these locks has significant cost during selector matching: * https://bugzilla.mozilla.org/show_bug.cgi?id=1311469 * https://bugzilla.mozilla.org/show_bug.cgi?id=1335941 * https://bugzilla.mozilla.org/show_bug.cgi?id=1339703 This PR introduce a mechanism to protect many objects with the same `RwLock` that only needs to be acquired once. In Stylo, there is one such lock per process (in a `lazy_static`), used for everything. I non-Stylo Servo, I originally intended to have one such lock per document (for author-origin stylesheets, and one per process for user-agent and user sytlesheets since they’re shared across documents, and never mutated anyway). However I failed to have the same document-specific (or pipeline-specific) `Arc` reachable from both `Document` nodes and `LayoutThread`. Recursively following callers lead me to include this `Arc` in `UnprivilegedPipelineContent`, but that needs to be serializable. So there is a second process-wide lock. This was previously #15998, closed accidentally. --- <!-- 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 - [ ] These changes fix #__ (github issue number if applicable). <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: bb54f0a429de0e8b8861f8071b6cf82f73622664 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 851230e57ac8775707df5f0f103be5feac81fc41
2017-03-20 00:31:19 +03:00
let element = GeckoElement(element);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let name = Atom::from_raw(name);
let animation = match data.stylist.get_animation(&name, element) {
Some(animation) => animation,
None => return false,
};
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let mut properties_set_at_current_offset = LonghandIdSet::new();
let mut properties_set_at_start = LonghandIdSet::new();
let mut properties_set_at_end = LonghandIdSet::new();
let mut has_complete_initial_keyframe = false;
let mut has_complete_final_keyframe = false;
let mut current_offset = -1.;
let writing_mode = style.writing_mode;
// Iterate over the keyframe rules backwards so we can drop overridden
// properties (since declarations in later rules override those in earlier
// ones).
for step in animation.steps.iter().rev() {
if step.start_percentage.0 != current_offset {
properties_set_at_current_offset.clear();
current_offset = step.start_percentage.0;
}
// Override timing_function if the keyframe has an animation-timing-function.
let timing_function = nsTimingFunction {
mTiming: match step.get_animation_timing_function(&guard) {
Some(val) => val.to_computed_value_without_context(),
None => (*inherited_timing_function).mTiming,
},
};
// Look for an existing keyframe with the same offset and timing
// function or else add a new keyframe at the beginning of the keyframe
// array.
let keyframe = Gecko_GetOrCreateKeyframeAtStart(
keyframes,
step.start_percentage.0 as f32,
&timing_function,
);
match step.value {
KeyframesStepValue::ComputedValues => {
// In KeyframesAnimation::from_keyframes if there is no 0% or
// 100% keyframe at all, we will create a 'ComputedValues' step
// to represent that all properties animated by the keyframes
// animation should be set to the underlying computed value for
// that keyframe.
let mut seen = LonghandIdSet::new();
for property in animation.properties_changed.iter() {
let property = property.to_physical(writing_mode);
if seen.contains(property) {
continue;
}
seen.insert(property);
Gecko_AppendPropertyValuePair(
&mut *(*keyframe).mPropertyValues,
property.to_nscsspropertyid(),
);
}
if current_offset == 0.0 {
has_complete_initial_keyframe = true;
} else if current_offset == 1.0 {
has_complete_final_keyframe = true;
}
},
KeyframesStepValue::Declarations { ref block } => {
let guard = block.read_with(&guard);
let mut custom_properties = PropertyDeclarationBlock::new();
// Filter out non-animatable properties and properties with
// !important.
//
// Also, iterate in reverse to respect the source order in case
// there are logical and physical longhands in the same block.
for declaration in guard.normal_declaration_iter().rev() {
let id = declaration.id();
let id = match id {
PropertyDeclarationId::Longhand(id) => {
// Skip the 'display' property because although it
// is animatable from SMIL, it should not be
// animatable from CSS Animations.
if id == LonghandId::Display {
continue;
}
if !id.is_animatable() {
continue;
}
id.to_physical(writing_mode)
},
PropertyDeclarationId::Custom(..) => {
custom_properties.push(declaration.clone(), Importance::Normal);
continue;
},
};
if properties_set_at_current_offset.contains(id) {
continue;
}
let pair = Gecko_AppendPropertyValuePair(
&mut *(*keyframe).mPropertyValues,
id.to_nscsspropertyid(),
);
(*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
global_style_data
.shared_lock
.wrap(PropertyDeclarationBlock::with_one(
declaration.to_physical(writing_mode),
Importance::Normal,
)),
));
if current_offset == 0.0 {
properties_set_at_start.insert(id);
} else if current_offset == 1.0 {
properties_set_at_end.insert(id);
}
properties_set_at_current_offset.insert(id);
}
if custom_properties.any_normal() {
let pair = Gecko_AppendPropertyValuePair(
&mut *(*keyframe).mPropertyValues,
nsCSSPropertyID::eCSSPropertyExtra_variable,
);
(*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
global_style_data.shared_lock.wrap(custom_properties),
));
}
},
}
}
let mut properties_changed = LonghandIdSet::new();
for property in animation.properties_changed.iter() {
properties_changed.insert(property.to_physical(writing_mode));
}
// Append property values that are missing in the initial or the final keyframes.
if !has_complete_initial_keyframe {
fill_in_missing_keyframe_values(
&properties_changed,
inherited_timing_function,
&properties_set_at_start,
Offset::Zero,
keyframes,
);
}
if !has_complete_final_keyframe {
fill_in_missing_keyframe_values(
&properties_changed,
inherited_timing_function,
&properties_set_at_end,
Offset::One,
keyframes,
);
}
true
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
raw_data: &RawServoStyleSet,
rules: &mut nsTArray<structs::nsFontFaceRuleContainer>,
) {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
debug_assert_eq!(rules.len(), 0);
let len: u32 = data
.stylist
.iter_extra_data_origins()
.map(|(d, _)| d.font_faces.len() as u32)
.sum();
// Reversed iterator because Gecko expects rules to appear sorted
// UserAgent first, Author last.
let font_face_iter = data
.stylist
.iter_extra_data_origins_rev()
.flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
unsafe { rules.set_len(len) };
for ((rule, origin), dest) in font_face_iter.zip(rules.iter_mut()) {
dest.mRule.set_arc_leaky(rule.clone());
dest.mOrigin = origin;
}
}
// XXX Ideally this should return a Option<&RawServoCounterStyleRule>,
// but we cannot, because the value from AtomicRefCell::borrow() can only
// live in this function, and thus anything derived from it cannot get the
// same lifetime as raw_data in parameter. See bug 1451543.
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
raw_data: &RawServoStyleSet,
name: *mut nsAtom,
) -> *const RawServoCounterStyleRule {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
Atom::with(name, |name| {
data.stylist
.iter_extra_data_origins()
.filter_map(|(d, _)| d.counter_styles.get(name))
.next()
.map_or(ptr::null(), |rule| rule.as_borrowed())
})
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
raw_data: &RawServoStyleSet,
) -> *mut gfxFontFeatureValueSet {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let has_rule = data
.stylist
.iter_extra_data_origins()
.any(|(d, _)| !d.font_feature_values.is_empty());
if !has_rule {
return ptr::null_mut();
}
let font_feature_values_iter = data
.stylist
.iter_extra_data_origins_rev()
.flat_map(|(d, _)| d.font_feature_values.iter());
let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
for src in font_feature_values_iter {
let rule = src.read_with(&guard);
rule.set_at_rules(set);
}
set
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
raw_data: &RawServoStyleSet,
parent_style_context: Option<&ComputedValues>,
declarations: &RawServoDeclarationBlock,
) -> Strong<ComputedValues> {
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let guards = StylesheetGuards::same(&guard);
let parent_style = match parent_style_context {
Some(parent) => &*parent,
None => doc_data.default_computed_values(),
};
let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
doc_data
.stylist
.compute_for_declarations::<GeckoElement>(&guards, parent_style, declarations.clone_arc())
.into()
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
sizes: *mut ServoStyleSetSizes,
raw_data: &RawServoStyleSet,
) {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
None,
);
let sizes = unsafe { sizes.as_mut() }.unwrap();
data.add_size_of(&mut ops, sizes);
}
#[no_mangle]
pub extern "C" fn Servo_UACache_AddSizeOf(
malloc_size_of: GeckoMallocSizeOf,
malloc_enclosing_size_of: GeckoMallocSizeOf,
sizes: *mut ServoStyleSetSizes,
) {
let mut ops = MallocSizeOfOps::new(
malloc_size_of.unwrap(),
Some(malloc_enclosing_size_of.unwrap()),
None,
);
let sizes = unsafe { sizes.as_mut() }.unwrap();
add_size_of_ua_cache(&mut ops, sizes);
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
raw_data: &RawServoStyleSet,
element: &RawGeckoElement,
local_name: *mut nsAtom,
) -> bool {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let element = GeckoElement(element);
unsafe {
Atom::with(local_name, |atom| {
servo: Merge #20597 - style: Implement the non-functional :host selector (from emilio:host); r=xidorn Kinda tricky because :host only matches rules on the shadow root where the rules come from. So we need to be careful during invalidation and style sharing. I didn't use the non_ts_pseudo_class_list bits because as soon as we implement the :host(..) bits we're going to need to special-case it anyway. The general schema is the following: * Rightmost featureless :host selectors are handled inserting them in the host_rules hashmap. Note that we only insert featureless stuff there. We could insert all of them and just filter during matching, but that's slightly annoying. * The other selectors, like non-featureless :host or what not, are added to the normal cascade data. This is harmless, since the shadow host rules are never matched against the host, so we know they'll just never match, and avoids adding more special-cases. * Featureless :host selectors to the left of a combinator are handled during matching, in the special-case of next_element_for_combinator in selectors. This prevents this from being more invasive, and keeps the usual fast path slim, but it's a bit hard to match the spec and the implementation. We could keep a copy of the SelectorIter instead in the matching context to make the handling of featureless-ness explicit in match_non_ts_pseudo_class, but we'd still need the special-case anyway, so I'm not fond of it. * We take advantage of one thing that makes this sound. As you may have noticed, if you had `root` element which is a ShadowRoot, and you matched something like `div:host` against it, using a MatchingContext with current_host == root, we'd incorrectly report a match. But this is impossible due to the following constraints: * Shadow root rules aren't matched against the host during styling (except these featureless selectors). * DOM APIs' current_host needs to be the _containing_ host, not the element itself if you're a Shadow host. Bug: 992245 Reviewed-by: xidorn MozReview-Commit-ID: KayYNfTXb5h Source-Repo: https://github.com/servo/servo Source-Revision: cb754b262747e7cab794411df55588f0f0b30b5e --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 2ebbb2578ff9dbadfe905ae501cd52bd61a9fe9a
2018-04-09 13:41:59 +03:00
data.stylist.any_applicable_rule_data(element, |data| {
data.might_have_attribute_dependency(atom)
})
})
}
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_HasStateDependency(
raw_data: &RawServoStyleSet,
element: &RawGeckoElement,
state: u64,
) -> bool {
let element = GeckoElement(element);
let state = ElementState::from_bits_truncate(state);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
data.stylist
.any_applicable_rule_data(element, |data| data.has_state_dependency(state))
}
#[no_mangle]
pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
raw_data: &RawServoStyleSet,
state: u64,
) -> bool {
let state = DocumentState::from_bits_truncate(state);
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
data.stylist.has_document_state_dependency(state)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_GetPropertyValue(
style: &ComputedValues,
prop: nsCSSPropertyID,
value: &mut nsAString,
) {
if let Ok(longhand) = LonghandId::from_nscsspropertyid(prop) {
style
.get_longhand_property_value(longhand, &mut CssWriter::new(value))
.unwrap();
return;
}
let shorthand =
ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
let mut block = PropertyDeclarationBlock::new();
// NOTE(emilio): We reuse the animation value machinery to avoid blowing up
// code size, but may need to come up with something different if ever care
// about supporting the cases that assert below. Fortunately we don't right
// now.
for longhand in shorthand.longhands() {
debug_assert!(
!longhand.is_logical(),
"This won't quite do the right thing if we want to serialize \
logical shorthands"
);
let animated = AnimationValue::from_computed_values(longhand, style).expect(
"Somebody tried to serialize a shorthand with \
non-animatable properties, would need more code \
to do this",
);
block.push(animated.uncompute(), Importance::Normal);
}
block.shorthand_to_css(shorthand, value).unwrap();
}
#[no_mangle]
pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
computed_values: &ComputedValues,
name: &nsACString,
value: &mut nsAString,
) -> bool {
let custom_properties = match computed_values.custom_properties() {
Some(p) => p,
None => return false,
};
let name = Atom::from(name.as_str_unchecked());
let computed_value = match custom_properties.get(&name) {
Some(v) => v,
None => return false,
};
computed_value.to_css(&mut CssWriter::new(value)).unwrap();
true
}
#[no_mangle]
pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
match computed_values.custom_properties() {
Some(p) => p.len() as u32,
None => 0,
}
}
#[no_mangle]
pub extern "C" fn Servo_GetCustomPropertyNameAt(
computed_values: &ComputedValues,
index: u32,
) -> *mut nsAtom {
let custom_properties = match computed_values.custom_properties() {
Some(p) => p,
None => return ptr::null_mut(),
};
let property_name = match custom_properties.get_index(index as usize) {
Some((key, _value)) => key,
None => return ptr::null_mut(),
};
property_name.as_ptr()
}
#[no_mangle]
Bug 1552708 - Use cbindgen for URIs. r=heycam This doesn't clean up as much as a whole, but it's a step in the right direction. In particular, it allows us to start using simple bindings for: * Filters * Shapes and images, almost. Need to: * Get rid of the complex -moz- gradient parsing (let layout.css.simple-moz-gradient.enabled get to release). * Counters, almost. Need to: * Share the Attr representation with Gecko, by not using Option<>. * Just another variant should be enough (ContentItem::{Attr,Prefixedattr}, maybe). Which in turn allows us to remove a whole lot of bindings in followups to this. The setup changes a bit. This also removes the double pointer I complained about while reviewing the shared UA sheet patches. The old setup is: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * UrlValueSource * Arc<CssUrlData> * load id * resolved uri * CORS mode. * ... ``` The new one removes the double reference to the url data via URLValue, and looks like: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * CorsMode * LoadData * load id * resolved URI ``` The LoadData is the only mutable bit that C++ can change, and is not used from Rust. Ideally, in the future, we could just use rust-url to resolve the URL after parsing or something, and make it all immutable. Maybe. I've verified that this approach still works with the UA sheet patches (via the LoadDataSource::Lazy). The reordering of mWillChange is to avoid nsStyleDisplay from going over the size limit. We want to split it up anyway in bug 1552587, but mBinding gains a tag member, which means that we were having a bit of extra padding. One thing I want to explore is to see if we can abuse rustc's non-zero optimizations to predict the layout from C++, but that's something to explore at some other point in time and with a lot of care and help from Michael (who sits next to me and works on rustc ;)). Differential Revision: https://phabricator.services.mozilla.com/D31742
2019-05-27 14:45:12 +03:00
pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
url.is_fragment()
}
#[no_mangle]
pub extern "C" fn Servo_ProcessInvalidations(
set: &RawServoStyleSet,
element: &RawGeckoElement,
snapshots: *const ServoElementSnapshotTable,
) {
debug_assert!(!snapshots.is_null());
let element = GeckoElement(element);
debug_assert!(element.has_snapshot());
debug_assert!(!element.handled_snapshot());
let mut data = element.mutate_data();
debug_assert!(data.is_some());
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let per_doc_data = PerDocumentStyleData::from_ffi(set).borrow();
let shared_style_context = create_shared_context(
&global_style_data,
&guard,
&per_doc_data,
TraversalFlags::empty(),
unsafe { &*snapshots },
);
let mut data = data.as_mut().map(|d| &mut **d);
if let Some(ref mut data) = data {
// FIXME(emilio): Ideally we could share the nth-index-cache across all
// the elements?
let result = data.invalidate_style_if_needed(
element,
&shared_style_context,
None,
&mut NthIndexCache::default(),
);
if result.has_invalidated_siblings() {
let parent = element
.traversal_parent()
.expect("How could we invalidate siblings without a common parent?");
unsafe {
parent.set_dirty_descendants();
bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
}
} else if result.has_invalidated_descendants() {
unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
} else if result.has_invalidated_self() {
unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
}
}
}
#[no_mangle]
pub extern "C" fn Servo_HasPendingRestyleAncestor(
element: &RawGeckoElement,
may_need_to_flush_layout: bool,
) -> bool {
let mut has_yet_to_be_styled = false;
let mut element = Some(GeckoElement(element));
while let Some(e) = element {
if e.has_any_animation() {
return true;
}
// If the element needs a frame, it means that we haven't styled it yet
// after it got inserted in the document, and thus we may need to do
// that for transitions and animations to trigger.
//
// This is a fast path in the common case, but `has_yet_to_be_styled` is
// the real check for this.
if e.needs_frame() {
return true;
}
let data = e.borrow_data();
if let Some(ref data) = data {
if !data.hint.is_empty() {
return true;
}
if has_yet_to_be_styled && !data.styles.is_display_none() {
return true;
}
// Ideally, DOM mutations wouldn't affect layout trees of siblings.
//
// In practice, this can happen because Gecko deals pretty badly
// with some kinds of content insertion and removals.
//
// If we may need to flush layout, we need frames to accurately
// determine whether we'll actually flush, so if we have to
// reconstruct we need to flush style, which is what will take care
// of ensuring that frames are constructed, even if the style itself
// is up-to-date.
if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
return true;
}
}
has_yet_to_be_styled = data.is_none();
element = e.traversal_parent();
}
false
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_Parse(
selector_list: &nsACString,
) -> OwnedOrNull<RawServoSelectorList> {
use style::selector_parser::SelectorParser;
let input = selector_list.as_str_unchecked();
let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input) {
Ok(selector_list) => selector_list,
Err(..) => return OwnedOrNull::null(),
};
Box::new(selector_list).into_ffi().maybe()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut RawServoSelectorList) {
SelectorList::drop_ffi(list)
}
fn parse_color(
value: &str,
error_reporter: Option<&dyn ParseErrorReporter>,
) -> Result<specified::Color, ()> {
let mut input = ParserInput::new(value);
let mut parser = Parser::new(&mut input);
let url_data = unsafe { dummy_url_data() };
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
error_reporter,
None,
);
let start_position = parser.position();
parser
.parse_entirely(|i| specified::Color::parse(&context, i))
.map_err(|err| {
if error_reporter.is_some() {
match err.kind {
ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {
let location = err.location.clone();
let error = ContextualParseError::UnsupportedValue(
parser.slice_from(start_position),
err,
);
context.log_css_error(location, error);
},
// Ignore other kinds of errors that might be reported, such as
// ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken),
// since Gecko doesn't report those to the error console.
_ => {},
}
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
parse_color(value.as_str_unchecked(), None).is_ok()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ComputeColor(
raw_data: Option<&RawServoStyleSet>,
current_color: structs::nscolor,
value: &nsACString,
result_color: &mut structs::nscolor,
was_current_color: *mut bool,
loader: *mut Loader,
) -> bool {
use style::gecko;
let current_color = gecko::values::convert_nscolor_to_rgba(current_color);
let reporter = loader.as_mut().and_then(|loader| {
// Make an ErrorReporter that will report errors as being "from DOM".
ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
});
let specified_color = match parse_color(
value.as_str_unchecked(),
reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
) {
Ok(c) => c,
Err(..) => return false,
};
let computed_color = match raw_data {
Some(raw_data) => {
let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let device = data.stylist.device();
let quirks_mode = data.stylist.quirks_mode();
Context::for_media_query_evaluation(device, quirks_mode, |context| {
specified_color.to_computed_color(Some(&context))
})
},
None => specified_color.to_computed_color(None),
};
let computed_color = match computed_color {
Some(c) => c,
None => return false,
};
let rgba = computed_color.to_rgba(current_color);
*result_color = gecko::values::convert_rgba_to_nscolor(&rgba);
if !was_current_color.is_null() {
*was_current_color = computed_color.is_currentcolor();
}
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
value: &nsAString,
result: *mut IntersectionObserverRootMargin,
) -> bool {
let value = value.to_string();
let result = result.as_mut().unwrap();
let mut input = ParserInput::new(&value);
let mut parser = Parser::new(&mut input);
let url_data = dummy_url_data();
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
match margin {
Ok(margin) => {
*result = margin;
true
},
Err(..) => false,
}
}
#[no_mangle]
pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
root_margin: &IntersectionObserverRootMargin,
result: &mut nsAString,
) {
let mut writer = CssWriter::new(result);
root_margin.to_css(&mut writer).unwrap();
}
#[no_mangle]
pub extern "C" fn Servo_ParseTransformIntoMatrix(
value: &nsACString,
contain_3d: &mut bool,
result: &mut structs::Matrix4x4Components,
) -> bool {
use style::properties::longhands::transform;
let string = unsafe { value.as_str_unchecked() };
let mut input = ParserInput::new(&string);
let mut parser = Parser::new(&mut input);
let context = ParserContext::new(
Origin::Author,
unsafe { dummy_url_data() },
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
Ok(t) => t,
Err(..) => return false,
};
let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
Ok(result) => result,
Err(..) => return false,
};
*result = m.to_array();
*contain_3d = is_3d;
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
value: &nsAString,
data: *mut URLExtraData,
family: &mut structs::RefPtr<structs::SharedFontList>,
style: &mut ComputedFontStyleDescriptor,
stretch: &mut f32,
weight: &mut f32,
) -> bool {
use style::properties::shorthands::font;
use style::values::computed::font::FontFamilyList;
use style::values::computed::font::FontWeight as ComputedFontWeight;
use style::values::generics::font::FontStyle as GenericFontStyle;
use style::values::specified::font::{
FontFamily, FontStretch, FontStyle, FontWeight, SpecifiedFontStyle,
};
let string = value.to_string();
let mut input = ParserInput::new(&string);
let mut parser = Parser::new(&mut input);
let url_data = UrlExtraData::from_ptr_ref(&data);
let context = ParserContext::new(
Origin::Author,
url_data,
Some(CssRuleType::FontFace),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
Ok(f) => f,
Err(..) => return false,
};
// The system font is not acceptable, so we return false.
match font.font_family {
FontFamily::Values(FontFamilyList::SharedFontList(list)) => family.set_move(list),
FontFamily::Values(list) => family.set_move(list.shared_font_list().clone()),
FontFamily::System(_) => return false,
}
let specified_font_style = match font.font_style {
FontStyle::Specified(ref s) => s,
FontStyle::System(_) => return false,
};
*style = match *specified_font_style {
GenericFontStyle::Normal => ComputedFontStyleDescriptor::Normal,
GenericFontStyle::Italic => ComputedFontStyleDescriptor::Italic,
GenericFontStyle::Oblique(ref angle) => {
let angle = SpecifiedFontStyle::compute_angle_degrees(angle);
ComputedFontStyleDescriptor::Oblique(angle, angle)
},
};
*stretch = match font.font_stretch {
FontStretch::Keyword(ref k) => k.compute().0,
FontStretch::Stretch(ref p) => p.get(),
FontStretch::System(_) => return false,
};
*weight = match font.font_weight {
FontWeight::Absolute(w) => w.compute().0,
// Resolve relative font weights against the initial of font-weight
// (normal, which is equivalent to 400).
FontWeight::Bolder => ComputedFontWeight::normal().bolder().0,
FontWeight::Lighter => ComputedFontWeight::normal().lighter().0,
FontWeight::System(_) => return false,
};
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SourceSizeList_Parse(
value: &nsACString,
) -> Owned<RawServoSourceSizeList> {
let value = value.as_str_unchecked();
let mut input = ParserInput::new(value);
let mut parser = Parser::new(&mut input);
let context = ParserContext::new(
Origin::Author,
dummy_url_data(),
Some(CssRuleType::Style),
ParsingMode::DEFAULT,
QuirksMode::NoQuirks,
None,
None,
);
// NB: Intentionally not calling parse_entirely.
let list = SourceSizeList::parse(&context, &mut parser);
Box::new(list).into_ffi()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
raw_data: &RawServoStyleSet,
list: Option<&RawServoSourceSizeList>,
) -> i32 {
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let device = doc_data.stylist.device();
let quirks_mode = doc_data.stylist.quirks_mode();
let result = match list {
Some(list) => SourceSizeList::from_ffi(list).evaluate(device, quirks_mode),
None => SourceSizeList::empty().evaluate(device, quirks_mode),
};
result.0
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut RawServoSourceSizeList) {
SourceSizeList::drop_ffi(list);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
root: &RawGeckoElement,
document_style: &RawServoStyleSet,
non_document_styles: &nsTArray<&RawServoAuthorStyles>,
states_changed: u64,
) {
use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
use style::invalidation::element::invalidator::TreeStyleInvalidator;
let document_data = PerDocumentStyleData::from_ffi(document_style).borrow();
let iter = document_data
.stylist
.iter_origins()
.map(|(data, _origin)| data)
.chain(non_document_styles.iter().map(|author_styles| {
let styles: &_ = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
&styles.data
}));
let root = GeckoElement(root);
let mut processor = DocumentStateInvalidationProcessor::new(
iter,
DocumentState::from_bits_truncate(states_changed),
root.as_node().owner_doc().quirks_mode(),
);
let result =
TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
.invalidate();
debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
if result.has_invalidated_descendants() {
bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
} else if result.has_invalidated_self() {
bindings::Gecko_NoteDirtyElement(root.0);
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
let name = name.as_str_unchecked();
match NonTSPseudoClass::parse_non_functional(name) {
None => 0,
// Ignore :any-link since it contains both visited and unvisited state.
Some(NonTSPseudoClass::AnyLink) => 0,
Some(pseudo_class) => pseudo_class.state_flag().bits(),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_UseCounters_Create() -> Owned<structs::StyleUseCounters> {
Box::<UseCounters>::default().into_ffi()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut structs::StyleUseCounters) {
UseCounters::drop_ffi(c);
}
#[no_mangle]
pub unsafe extern "C" fn Servo_UseCounters_Merge(
doc_counters: &UseCounters,
sheet_counters: &UseCounters,
) {
doc_counters.merge(sheet_counters)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
use_counters: &UseCounters,
id: nsCSSPropertyID,
) -> bool {
let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
use_counters.non_custom_properties.recorded(id)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
use_counters: &UseCounters,
p: CountedUnknownProperty,
) -> bool {
use_counters.counted_unknown_properties.recorded(p)
}
#[no_mangle]
pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
use_counters: &UseCounters,
property: &nsACString,
known_prop: *mut bool,
) -> bool {
*known_prop = false;
let prop_name = property.as_str_unchecked();
if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
if let Some(id) = p.non_custom_id() {
*known_prop = true;
return use_counters.non_custom_properties.recorded(id);
}
}
if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
*known_prop = true;
return use_counters.counted_unknown_properties.recorded(p);
}
false
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
buffer: *mut u8,
len: usize,
) -> *mut RawServoSharedMemoryBuilder {
let mut builder = Box::new(SharedMemoryBuilder::new(buffer, len));
// We have Arc<UnparsedValue>s in style sheets due to CSS variables being
// used in shorthand property declarations. There aren't many, though,
// and they aren't big, so we just allow their duplication for now.
builder.add_allowed_duplication_type::<UnparsedValue>();
Box::into_raw(builder) as *mut _
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
builder: &mut RawServoSharedMemoryBuilder,
raw_contents: &RawServoStyleSheetContents,
error_message: &mut nsACString,
) -> *const ServoCssRules {
let builder = SharedMemoryBuilder::from_ffi_mut(builder);
let contents = StylesheetContents::as_arc(&raw_contents);
// Assert some things we assume when we create a style sheet from shared
// memory.
debug_assert_eq!(contents.origin, Origin::UserAgent);
debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
debug_assert!(contents.source_map_url.read().is_none());
debug_assert!(contents.source_url.read().is_none());
match builder.write(&contents.rules) {
Ok(rules_ptr) => {
(*rules_ptr).with_raw_offset_arc(|arc| *Locked::arc_as_borrowed(arc) as *const _)
},
Err(message) => {
error_message.assign(&message);
ptr::null()
},
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
builder: &mut RawServoSharedMemoryBuilder,
) -> usize {
let builder = SharedMemoryBuilder::from_ffi_mut(builder);
builder.len()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut RawServoSharedMemoryBuilder) {
SharedMemoryBuilder::drop_ffi(builder)
}
/// Returns a unique pointer to a clone of the shape image.
///
/// Probably temporary, as we move more stuff to cbindgen.
#[no_mangle]
#[must_use]
pub unsafe extern "C" fn Servo_CloneBasicShape(
v: &computed::basic_shape::BasicShape,
) -> *mut computed::basic_shape::BasicShape {
Box::into_raw(Box::new(v.clone()))
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
}
Bug 1552708 - Use cbindgen for URIs. r=heycam This doesn't clean up as much as a whole, but it's a step in the right direction. In particular, it allows us to start using simple bindings for: * Filters * Shapes and images, almost. Need to: * Get rid of the complex -moz- gradient parsing (let layout.css.simple-moz-gradient.enabled get to release). * Counters, almost. Need to: * Share the Attr representation with Gecko, by not using Option<>. * Just another variant should be enough (ContentItem::{Attr,Prefixedattr}, maybe). Which in turn allows us to remove a whole lot of bindings in followups to this. The setup changes a bit. This also removes the double pointer I complained about while reviewing the shared UA sheet patches. The old setup is: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * UrlValueSource * Arc<CssUrlData> * load id * resolved uri * CORS mode. * ... ``` The new one removes the double reference to the url data via URLValue, and looks like: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * CorsMode * LoadData * load id * resolved URI ``` The LoadData is the only mutable bit that C++ can change, and is not used from Rust. Ideally, in the future, we could just use rust-url to resolve the URL after parsing or something, and make it all immutable. Maybe. I've verified that this approach still works with the UA sheet patches (via the LoadDataSource::Lazy). The reordering of mWillChange is to avoid nsStyleDisplay from going over the size limit. We want to split it up anyway in bug 1552587, but mBinding gains a tag member, which means that we were having a bit of extra padding. One thing I want to explore is to see if we can abuse rustc's non-zero optimizations to predict the layout from C++, but that's something to explore at some other point in time and with a lot of care and help from Michael (who sits next to me and works on rustc ;)). Differential Revision: https://phabricator.services.mozilla.com/D31742
2019-05-27 14:45:12 +03:00
#[no_mangle]
pub unsafe extern "C" fn Servo_LoadData_GetLazy(
source: &url::LoadDataSource,
) -> *const url::LoadData {
Bug 1552708 - Use cbindgen for URIs. r=heycam This doesn't clean up as much as a whole, but it's a step in the right direction. In particular, it allows us to start using simple bindings for: * Filters * Shapes and images, almost. Need to: * Get rid of the complex -moz- gradient parsing (let layout.css.simple-moz-gradient.enabled get to release). * Counters, almost. Need to: * Share the Attr representation with Gecko, by not using Option<>. * Just another variant should be enough (ContentItem::{Attr,Prefixedattr}, maybe). Which in turn allows us to remove a whole lot of bindings in followups to this. The setup changes a bit. This also removes the double pointer I complained about while reviewing the shared UA sheet patches. The old setup is: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * UrlValueSource * Arc<CssUrlData> * load id * resolved uri * CORS mode. * ... ``` The new one removes the double reference to the url data via URLValue, and looks like: ``` SpecifiedUrl * CssUrl * Arc<CssUrlData> * String * UrlExtraData * CorsMode * LoadData * load id * resolved URI ``` The LoadData is the only mutable bit that C++ can change, and is not used from Rust. Ideally, in the future, we could just use rust-url to resolve the URL after parsing or something, and make it all immutable. Maybe. I've verified that this approach still works with the UA sheet patches (via the LoadDataSource::Lazy). The reordering of mWillChange is to avoid nsStyleDisplay from going over the size limit. We want to split it up anyway in bug 1552587, but mBinding gains a tag member, which means that we were having a bit of extra padding. One thing I want to explore is to see if we can abuse rustc's non-zero optimizations to predict the layout from C++, but that's something to explore at some other point in time and with a lot of care and help from Michael (who sits next to me and works on rustc ;)). Differential Revision: https://phabricator.services.mozilla.com/D31742
2019-05-27 14:45:12 +03:00
source.get()
}
#[no_mangle]
pub extern "C" fn Servo_LengthPercentage_ToCss(
lp: &computed::LengthPercentage,
result: &mut nsAString,
) {
lp.to_css(&mut CssWriter::new(result)).unwrap();
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CursorKind_Parse(
cursor: &nsACString,
result: &mut computed::ui::CursorKind,
) -> bool {
match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
Ok(c) => {
*result = c;
true
},
Err(..) => false,
}
}