1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5 use super::error_reporter::ErrorReporter;
6 use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
7 use bincode::{deserialize, serialize};
8 use cssparser::ToCss as ParserToCss;
9 use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation, UnicodeRange};
10 use malloc_size_of::MallocSizeOfOps;
11 use nsstring::{nsCString, nsString};
12 use selectors::matching::{matches_selector, MatchingContext, MatchingMode, VisitedHandlingMode};
13 use selectors::{NthIndexCache, SelectorList};
14 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
15 use smallvec::SmallVec;
16 use std::cell::RefCell;
17 use std::collections::BTreeSet;
18 use std::fmt::Write;
19 use std::iter;
20 use std::os::raw::c_void;
21 use std::ptr;
22 use style::applicable_declarations::ApplicableDeclarationBlock;
23 use style::author_styles::AuthorStyles;
24 use style::context::ThreadLocalStyleContext;
25 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
26 use style::counter_style;
27 use style::data::{self, ElementStyles};
28 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
29 use style::driver;
30 use style::element_state::{DocumentState, ElementState};
31 use style::error_reporting::{ContextualParseError, ParseErrorReporter};
32 use style::font_face::{self, ComputedFontStyleDescriptor, FontFaceSourceListComponent, Source};
33 use style::font_metrics::{get_metrics_provider_for_product, FontMetricsProvider};
34 use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
35 use style::gecko::restyle_damage::GeckoRestyleDamage;
36 use style::gecko::selector_parser::{NonTSPseudoClass, PseudoElement};
37 use style::gecko::traversal::RecalcStyleOnly;
38 use style::gecko::url;
39 use style::gecko::wrapper::{GeckoElement, GeckoNode};
40 use style::gecko_bindings::bindings;
41 use style::gecko_bindings::bindings::nsACString;
42 use style::gecko_bindings::bindings::nsAString;
43 use style::gecko_bindings::bindings::Gecko_AddPropertyToSet;
44 use style::gecko_bindings::bindings::Gecko_AppendPropertyValuePair;
45 use style::gecko_bindings::bindings::Gecko_ConstructFontFeatureValueSet;
46 use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
47 use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
48 use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
49 use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
50 use style::gecko_bindings::structs;
51 use style::gecko_bindings::structs::gfxFontFeatureValueSet;
52 use style::gecko_bindings::structs::ipc::ByteBuf;
53 use style::gecko_bindings::structs::nsAtom;
54 use style::gecko_bindings::structs::nsCSSCounterDesc;
55 use style::gecko_bindings::structs::nsCSSFontDesc;
56 use style::gecko_bindings::structs::nsCSSPropertyID;
57 use style::gecko_bindings::structs::nsChangeHint;
58 use style::gecko_bindings::structs::nsCompatibility;
59 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
60 use style::gecko_bindings::structs::nsTArray;
61 use style::gecko_bindings::structs::nsTimingFunction;
62 use style::gecko_bindings::structs::nsresult;
63 use style::gecko_bindings::structs::AtomArray;
64 use style::gecko_bindings::structs::CallerType;
65 use style::gecko_bindings::structs::CompositeOperation;
66 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
67 use style::gecko_bindings::structs::IterationCompositeOperation;
68 use style::gecko_bindings::structs::Loader;
69 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
70 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
71 use style::gecko_bindings::structs::OriginFlags;
72 use style::gecko_bindings::structs::PropertyValuePair;
73 use style::gecko_bindings::structs::PseudoStyleType;
74 use style::gecko_bindings::structs::RawServoSelectorList;
75 use style::gecko_bindings::structs::RawServoSourceSizeList;
76 use style::gecko_bindings::structs::RawServoStyleRule;
77 use style::gecko_bindings::structs::SeenPtrs;
78 use style::gecko_bindings::structs::ServoElementSnapshotTable;
79 use style::gecko_bindings::structs::ServoStyleSetSizes;
80 use style::gecko_bindings::structs::ServoTraversalFlags;
81 use style::gecko_bindings::structs::SheetLoadData;
82 use style::gecko_bindings::structs::SheetLoadDataHolder;
83 use style::gecko_bindings::structs::SheetParsingMode;
84 use style::gecko_bindings::structs::StyleRuleInclusion;
85 use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
86 use style::gecko_bindings::structs::URLExtraData;
87 use style::gecko_bindings::structs::{nsINode as RawGeckoNode, Element as RawGeckoElement};
88 use style::gecko_bindings::structs::{
89 RawServoAnimationValue, RawServoAuthorStyles, RawServoCounterStyleRule,
90 RawServoDeclarationBlock, RawServoFontFaceRule, RawServoFontFeatureValuesRule,
91 RawServoImportRule, RawServoKeyframe, RawServoKeyframesRule, RawServoMediaList,
92 RawServoMediaRule, RawServoMozDocumentRule, RawServoNamespaceRule, RawServoPageRule,
93 RawServoSharedMemoryBuilder, RawServoStyleSet, RawServoStyleSheetContents,
94 RawServoSupportsRule, ServoCssRules,
95 };
96 use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
97 use style::gecko_bindings::sugar::ownership::{
98 HasBoxFFI, HasSimpleFFI, Owned, OwnedOrNull, Strong,
99 };
100 use style::gecko_bindings::sugar::refptr::RefPtr;
101 use style::global_style_data::{GlobalStyleData, GLOBAL_STYLE_DATA, StyleThreadPool, STYLE_THREAD_POOL};
102 use style::invalidation::element::restyle_hints::RestyleHint;
103 use style::media_queries::MediaList;
104 use style::parser::{self, Parse, ParserContext};
105 use style::profiler_label;
106 use style::properties::animated_properties::{AnimationValue, AnimationValueMap};
107 use style::properties::{parse_one_declaration_into, parse_style_attribute};
108 use style::properties::{ComputedValues, CountedUnknownProperty, Importance, NonCustomPropertyId};
109 use style::properties::{LonghandId, LonghandIdSet, PropertyDeclarationBlock, PropertyId};
110 use style::properties::{PropertyDeclarationId, ShorthandId};
111 use style::properties::{SourcePropertyDeclaration, StyleBuilder, UnparsedValue};
112 use style::rule_cache::RuleCacheConditions;
113 use style::rule_tree::{CascadeLevel, StrongRuleNode};
114 use style::selector_parser::PseudoElementCascadeType;
115 use style::shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards, ToCssWithGuard};
116 use style::string_cache::{Atom, WeakAtom};
117 use style::style_adjuster::StyleAdjuster;
118 use style::stylesheets::import_rule::ImportSheet;
119 use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
120 use style::stylesheets::supports_rule::parse_condition_or_declaration;
121 use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
122 use style::stylesheets::{CounterStyleRule, CssRule, CssRuleType, CssRules, CssRulesHelpers};
123 use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, ImportRule};
124 use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
125 use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule, UrlExtraData};
126 use style::stylesheets::{SanitizationData, SanitizationKind, AllowImportRules};
127 use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
128 use style::thread_state;
129 use style::timer::Timer;
130 use style::traversal::resolve_style;
131 use style::traversal::DomTraversal;
132 use style::traversal_flags::{self, TraversalFlags};
133 use style::use_counters::UseCounters;
134 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
135 use style::values::computed::{self, Context, ToComputedValue};
136 use style::values::distance::ComputeSquaredDistance;
137 use style::values::specified;
138 use style::values::specified::gecko::IntersectionObserverRootMargin;
139 use style::values::specified::source_size_list::SourceSizeList;
140 use style::values::{CustomIdent, KeyframesName};
141 use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
142 use to_shmem::SharedMemoryBuilder;
143
144 trait ClosureHelper {
invoke(&self)145 fn invoke(&self);
146 }
147
148 impl ClosureHelper for DeclarationBlockMutationClosure {
149 #[inline]
invoke(&self)150 fn invoke(&self) {
151 if let Some(function) = self.function.as_ref() {
152 unsafe { function(self.data) };
153 }
154 }
155 }
156
157 /*
158 * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
159 * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
160 * those signatures as well, giving us a second declaration of all the Servo_* functions in this
161 * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
162 * depend on but good enough for our purposes.
163 */
164
165 // A dummy url data for where we don't pass url data in.
166 // We need to get rid of this sooner than later.
167 static mut DUMMY_URL_DATA: *mut URLExtraData = 0 as *mut _;
168
169 #[no_mangle]
Servo_Initialize(dummy_url_data: *mut URLExtraData)170 pub unsafe extern "C" fn Servo_Initialize(dummy_url_data: *mut URLExtraData) {
171 use style::gecko_bindings::sugar::origin_flags;
172
173 // Pretend that we're a Servo Layout thread, to make some assertions happy.
174 thread_state::initialize(thread_state::ThreadState::LAYOUT);
175
176 // Perform some debug-only runtime assertions.
177 origin_flags::assert_flags_match();
178 parser::assert_parsing_mode_match();
179 traversal_flags::assert_traversal_flags_match();
180 specified::font::assert_variant_east_asian_matches();
181 specified::font::assert_variant_ligatures_matches();
182
183 DUMMY_URL_DATA = dummy_url_data;
184 }
185
186 #[no_mangle]
Servo_Shutdown()187 pub unsafe extern "C" fn Servo_Shutdown() {
188 DUMMY_URL_DATA = ptr::null_mut();
189 Stylist::shutdown();
190 url::shutdown();
191 }
192
193 #[inline(always)]
dummy_url_data() -> &'static UrlExtraData194 unsafe fn dummy_url_data() -> &'static UrlExtraData {
195 UrlExtraData::from_ptr_ref(&DUMMY_URL_DATA)
196 }
197
198 #[allow(dead_code)]
is_main_thread() -> bool199 fn is_main_thread() -> bool {
200 unsafe { bindings::Gecko_IsMainThread() }
201 }
202
203 #[allow(dead_code)]
is_in_servo_traversal() -> bool204 fn is_in_servo_traversal() -> bool {
205 unsafe { bindings::Gecko_IsInServoTraversal() }
206 }
207
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>208 fn create_shared_context<'a>(
209 global_style_data: &GlobalStyleData,
210 guard: &'a SharedRwLockReadGuard,
211 per_doc_data: &'a PerDocumentStyleDataImpl,
212 traversal_flags: TraversalFlags,
213 snapshot_map: &'a ServoElementSnapshotTable,
214 ) -> SharedStyleContext<'a> {
215 SharedStyleContext {
216 stylist: &per_doc_data.stylist,
217 visited_styles_enabled: per_doc_data.visited_styles_enabled(),
218 options: global_style_data.options.clone(),
219 guards: StylesheetGuards::same(guard),
220 timer: Timer::new(),
221 traversal_flags,
222 snapshot_map,
223 }
224 }
225
traverse_subtree( element: GeckoElement, global_style_data: &GlobalStyleData, per_doc_data: &PerDocumentStyleDataImpl, guard: &SharedRwLockReadGuard, traversal_flags: TraversalFlags, snapshots: &ServoElementSnapshotTable, )226 fn traverse_subtree(
227 element: GeckoElement,
228 global_style_data: &GlobalStyleData,
229 per_doc_data: &PerDocumentStyleDataImpl,
230 guard: &SharedRwLockReadGuard,
231 traversal_flags: TraversalFlags,
232 snapshots: &ServoElementSnapshotTable,
233 ) {
234 let shared_style_context = create_shared_context(
235 &global_style_data,
236 &guard,
237 &per_doc_data,
238 traversal_flags,
239 snapshots,
240 );
241
242 let token = RecalcStyleOnly::pre_traverse(element, &shared_style_context);
243
244 if !token.should_traverse() {
245 return;
246 }
247
248 debug!("Traversing subtree from {:?}", element);
249
250 let thread_pool_holder = &*STYLE_THREAD_POOL;
251 let pool;
252 let thread_pool = if traversal_flags.contains(TraversalFlags::ParallelTraversal) {
253 pool = thread_pool_holder.pool();
254 pool.as_ref()
255 } else {
256 None
257 };
258
259 let traversal = RecalcStyleOnly::new(shared_style_context);
260 driver::traverse_dom(&traversal, token, thread_pool);
261 }
262
263 /// Traverses the subtree rooted at `root` for restyling.
264 ///
265 /// Returns whether the root was restyled. Whether anything else was restyled or
266 /// not can be inferred from the dirty bits in the rest of the tree.
267 #[no_mangle]
Servo_TraverseSubtree( root: &RawGeckoElement, raw_data: &RawServoStyleSet, snapshots: *const ServoElementSnapshotTable, raw_flags: ServoTraversalFlags, ) -> bool268 pub extern "C" fn Servo_TraverseSubtree(
269 root: &RawGeckoElement,
270 raw_data: &RawServoStyleSet,
271 snapshots: *const ServoElementSnapshotTable,
272 raw_flags: ServoTraversalFlags,
273 ) -> bool {
274 let traversal_flags = TraversalFlags::from_bits_truncate(raw_flags);
275 debug_assert!(!snapshots.is_null());
276
277 let element = GeckoElement(root);
278
279 debug!("Servo_TraverseSubtree (flags={:?})", traversal_flags);
280 debug!("{:?}", ShowSubtreeData(element.as_node()));
281
282 if cfg!(debug_assertions) {
283 if let Some(parent) = element.traversal_parent() {
284 let data = parent
285 .borrow_data()
286 .expect("Styling element with unstyled parent");
287 assert!(
288 !data.styles.is_display_none(),
289 "Styling element with display: none parent"
290 );
291 }
292 }
293
294 let needs_animation_only_restyle =
295 element.has_animation_only_dirty_descendants() || element.has_animation_restyle_hints();
296
297 let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
298 debug_assert!(!per_doc_data.stylist.stylesheets_have_changed());
299
300 let global_style_data = &*GLOBAL_STYLE_DATA;
301 let guard = global_style_data.shared_lock.read();
302
303 let was_initial_style = !element.has_data();
304
305 if needs_animation_only_restyle {
306 debug!(
307 "Servo_TraverseSubtree doing animation-only restyle (aodd={})",
308 element.has_animation_only_dirty_descendants()
309 );
310 traverse_subtree(
311 element,
312 &global_style_data,
313 &per_doc_data,
314 &guard,
315 traversal_flags | TraversalFlags::AnimationOnly,
316 unsafe { &*snapshots },
317 );
318 }
319
320 traverse_subtree(
321 element,
322 &global_style_data,
323 &per_doc_data,
324 &guard,
325 traversal_flags,
326 unsafe { &*snapshots },
327 );
328
329 debug!(
330 "Servo_TraverseSubtree complete (dd={}, aodd={}, lfcd={}, lfc={}, data={:?})",
331 element.has_dirty_descendants(),
332 element.has_animation_only_dirty_descendants(),
333 element.descendants_need_frames(),
334 element.needs_frame(),
335 element.borrow_data().unwrap()
336 );
337
338 if was_initial_style {
339 debug_assert!(!element.borrow_data().unwrap().contains_restyle_data());
340 false
341 } else {
342 let element_was_restyled = element.borrow_data().unwrap().contains_restyle_data();
343 element_was_restyled
344 }
345 }
346
347 /// Checks whether the rule tree has crossed its threshold for unused nodes, and
348 /// if so, frees them.
349 #[no_mangle]
Servo_MaybeGCRuleTree(raw_data: &RawServoStyleSet)350 pub extern "C" fn Servo_MaybeGCRuleTree(raw_data: &RawServoStyleSet) {
351 let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
352 per_doc_data.stylist.rule_tree().maybe_gc();
353 }
354
355 #[no_mangle]
Servo_AnimationValues_Interpolate( from: &RawServoAnimationValue, to: &RawServoAnimationValue, progress: f64, ) -> Strong<RawServoAnimationValue>356 pub extern "C" fn Servo_AnimationValues_Interpolate(
357 from: &RawServoAnimationValue,
358 to: &RawServoAnimationValue,
359 progress: f64,
360 ) -> Strong<RawServoAnimationValue> {
361 let from_value = AnimationValue::as_arc(&from);
362 let to_value = AnimationValue::as_arc(&to);
363 if let Ok(value) = from_value.animate(to_value, Procedure::Interpolate { progress }) {
364 Arc::new(value).into_strong()
365 } else {
366 Strong::null()
367 }
368 }
369
370 #[no_mangle]
Servo_AnimationValues_IsInterpolable( from: &RawServoAnimationValue, to: &RawServoAnimationValue, ) -> bool371 pub extern "C" fn Servo_AnimationValues_IsInterpolable(
372 from: &RawServoAnimationValue,
373 to: &RawServoAnimationValue,
374 ) -> bool {
375 let from_value = AnimationValue::as_arc(&from);
376 let to_value = AnimationValue::as_arc(&to);
377 from_value
378 .animate(to_value, Procedure::Interpolate { progress: 0.5 })
379 .is_ok()
380 }
381
382 #[no_mangle]
Servo_AnimationValues_Add( a: &RawServoAnimationValue, b: &RawServoAnimationValue, ) -> Strong<RawServoAnimationValue>383 pub extern "C" fn Servo_AnimationValues_Add(
384 a: &RawServoAnimationValue,
385 b: &RawServoAnimationValue,
386 ) -> Strong<RawServoAnimationValue> {
387 let a_value = AnimationValue::as_arc(&a);
388 let b_value = AnimationValue::as_arc(&b);
389 if let Ok(value) = a_value.animate(b_value, Procedure::Add) {
390 Arc::new(value).into_strong()
391 } else {
392 Strong::null()
393 }
394 }
395
396 #[no_mangle]
Servo_AnimationValues_Accumulate( a: &RawServoAnimationValue, b: &RawServoAnimationValue, count: u64, ) -> Strong<RawServoAnimationValue>397 pub extern "C" fn Servo_AnimationValues_Accumulate(
398 a: &RawServoAnimationValue,
399 b: &RawServoAnimationValue,
400 count: u64,
401 ) -> Strong<RawServoAnimationValue> {
402 let a_value = AnimationValue::as_arc(&a);
403 let b_value = AnimationValue::as_arc(&b);
404 if let Ok(value) = a_value.animate(b_value, Procedure::Accumulate { count }) {
405 Arc::new(value).into_strong()
406 } else {
407 Strong::null()
408 }
409 }
410
411 #[no_mangle]
Servo_AnimationValues_GetZeroValue( value_to_match: &RawServoAnimationValue, ) -> Strong<RawServoAnimationValue>412 pub extern "C" fn Servo_AnimationValues_GetZeroValue(
413 value_to_match: &RawServoAnimationValue,
414 ) -> Strong<RawServoAnimationValue> {
415 let value_to_match = AnimationValue::as_arc(&value_to_match);
416 if let Ok(zero_value) = value_to_match.to_animated_zero() {
417 Arc::new(zero_value).into_strong()
418 } else {
419 Strong::null()
420 }
421 }
422
423 #[no_mangle]
Servo_AnimationValues_ComputeDistance( from: &RawServoAnimationValue, to: &RawServoAnimationValue, ) -> f64424 pub extern "C" fn Servo_AnimationValues_ComputeDistance(
425 from: &RawServoAnimationValue,
426 to: &RawServoAnimationValue,
427 ) -> f64 {
428 let from_value = AnimationValue::as_arc(&from);
429 let to_value = AnimationValue::as_arc(&to);
430 // If compute_squared_distance() failed, this function will return negative value
431 // in order to check whether we support the specified paced animation values.
432 from_value
433 .compute_squared_distance(to_value)
434 .map(|d| d.sqrt())
435 .unwrap_or(-1.0)
436 }
437
438 /// Compute one of the endpoints for the interpolation interval, compositing it with the
439 /// underlying value if needed.
440 /// An None returned value means, "Just use endpoint_value as-is."
441 /// It is the responsibility of the caller to ensure that |underlying_value| is provided
442 /// when it will be used.
composite_endpoint( endpoint_value: Option<&RawOffsetArc<AnimationValue>>, composite: CompositeOperation, underlying_value: Option<&AnimationValue>, ) -> Option<AnimationValue>443 fn composite_endpoint(
444 endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
445 composite: CompositeOperation,
446 underlying_value: Option<&AnimationValue>,
447 ) -> Option<AnimationValue> {
448 match endpoint_value {
449 Some(endpoint_value) => match composite {
450 CompositeOperation::Add => underlying_value
451 .expect("We should have an underlying_value")
452 .animate(endpoint_value, Procedure::Add)
453 .ok(),
454 CompositeOperation::Accumulate => underlying_value
455 .expect("We should have an underlying value")
456 .animate(endpoint_value, Procedure::Accumulate { count: 1 })
457 .ok(),
458 _ => None,
459 },
460 None => underlying_value.map(|v| v.clone()),
461 }
462 }
463
464 /// Accumulate one of the endpoints of the animation interval.
465 /// A returned value of None means, "Just use endpoint_value as-is."
accumulate_endpoint( endpoint_value: Option<&RawOffsetArc<AnimationValue>>, composited_value: Option<AnimationValue>, last_value: &AnimationValue, current_iteration: u64, ) -> Option<AnimationValue>466 fn accumulate_endpoint(
467 endpoint_value: Option<&RawOffsetArc<AnimationValue>>,
468 composited_value: Option<AnimationValue>,
469 last_value: &AnimationValue,
470 current_iteration: u64,
471 ) -> Option<AnimationValue> {
472 debug_assert!(
473 endpoint_value.is_some() || composited_value.is_some(),
474 "Should have a suitable value to use"
475 );
476
477 let count = current_iteration;
478 match composited_value {
479 Some(endpoint) => last_value
480 .animate(&endpoint, Procedure::Accumulate { count })
481 .ok()
482 .or(Some(endpoint)),
483 None => last_value
484 .animate(endpoint_value.unwrap(), Procedure::Accumulate { count })
485 .ok(),
486 }
487 }
488
489 /// Compose the animation segment. We composite it with the underlying_value and last_value if
490 /// needed.
491 /// The caller is responsible for providing an underlying value and last value
492 /// in all situations where there are needed.
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, ) -> AnimationValue493 fn compose_animation_segment(
494 segment: &structs::AnimationPropertySegment,
495 underlying_value: Option<&AnimationValue>,
496 last_value: Option<&AnimationValue>,
497 iteration_composite: IterationCompositeOperation,
498 current_iteration: u64,
499 total_progress: f64,
500 segment_progress: f64,
501 ) -> AnimationValue {
502 // Extract keyframe values.
503 let raw_from_value;
504 let keyframe_from_value = if !segment.mFromValue.mServo.mRawPtr.is_null() {
505 raw_from_value = unsafe { &*segment.mFromValue.mServo.mRawPtr };
506 Some(AnimationValue::as_arc(&raw_from_value))
507 } else {
508 None
509 };
510
511 let raw_to_value;
512 let keyframe_to_value = if !segment.mToValue.mServo.mRawPtr.is_null() {
513 raw_to_value = unsafe { &*segment.mToValue.mServo.mRawPtr };
514 Some(AnimationValue::as_arc(&raw_to_value))
515 } else {
516 None
517 };
518
519 let mut composited_from_value = composite_endpoint(
520 keyframe_from_value,
521 segment.mFromComposite,
522 underlying_value,
523 );
524 let mut composited_to_value =
525 composite_endpoint(keyframe_to_value, segment.mToComposite, underlying_value);
526
527 debug_assert!(
528 keyframe_from_value.is_some() || composited_from_value.is_some(),
529 "Should have a suitable from value to use"
530 );
531 debug_assert!(
532 keyframe_to_value.is_some() || composited_to_value.is_some(),
533 "Should have a suitable to value to use"
534 );
535
536 // Apply iteration composite behavior.
537 if iteration_composite == IterationCompositeOperation::Accumulate && current_iteration > 0 {
538 let last_value = last_value
539 .unwrap_or_else(|| underlying_value.expect("Should have a valid underlying value"));
540
541 composited_from_value = accumulate_endpoint(
542 keyframe_from_value,
543 composited_from_value,
544 last_value,
545 current_iteration,
546 );
547 composited_to_value = accumulate_endpoint(
548 keyframe_to_value,
549 composited_to_value,
550 last_value,
551 current_iteration,
552 );
553 }
554
555 // Use the composited value if there is one, otherwise, use the original keyframe value.
556 let from = composited_from_value
557 .as_ref()
558 .unwrap_or_else(|| keyframe_from_value.unwrap());
559 let to = composited_to_value
560 .as_ref()
561 .unwrap_or_else(|| keyframe_to_value.unwrap());
562
563 if segment.mToKey == segment.mFromKey {
564 return if total_progress < 0. {
565 from.clone()
566 } else {
567 to.clone()
568 };
569 }
570
571 match from.animate(
572 to,
573 Procedure::Interpolate {
574 progress: segment_progress,
575 },
576 ) {
577 Ok(value) => value,
578 _ => {
579 if segment_progress < 0.5 {
580 from.clone()
581 } else {
582 to.clone()
583 }
584 },
585 }
586 }
587
588 #[no_mangle]
Servo_ComposeAnimationSegment( segment: &structs::AnimationPropertySegment, underlying_value: Option<&RawServoAnimationValue>, last_value: Option<&RawServoAnimationValue>, iteration_composite: IterationCompositeOperation, progress: f64, current_iteration: u64, ) -> Strong<RawServoAnimationValue>589 pub extern "C" fn Servo_ComposeAnimationSegment(
590 segment: &structs::AnimationPropertySegment,
591 underlying_value: Option<&RawServoAnimationValue>,
592 last_value: Option<&RawServoAnimationValue>,
593 iteration_composite: IterationCompositeOperation,
594 progress: f64,
595 current_iteration: u64,
596 ) -> Strong<RawServoAnimationValue> {
597 let underlying_value = AnimationValue::arc_from_borrowed(&underlying_value).map(|v| &**v);
598 let last_value = AnimationValue::arc_from_borrowed(&last_value).map(|v| &**v);
599 let result = compose_animation_segment(
600 segment,
601 underlying_value,
602 last_value,
603 iteration_composite,
604 current_iteration,
605 progress,
606 progress,
607 );
608 Arc::new(result).into_strong()
609 }
610
611 #[no_mangle]
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, )612 pub extern "C" fn Servo_AnimationCompose(
613 raw_value_map: &mut structs::RawServoAnimationValueMap,
614 base_values: &structs::RawServoAnimationValueTable,
615 css_property: nsCSSPropertyID,
616 segment: &structs::AnimationPropertySegment,
617 last_segment: &structs::AnimationPropertySegment,
618 computed_timing: &structs::ComputedTiming,
619 iteration_composite: IterationCompositeOperation,
620 ) {
621 use style::gecko_bindings::bindings::Gecko_AnimationGetBaseStyle;
622 use style::gecko_bindings::bindings::Gecko_GetPositionInSegment;
623 use style::gecko_bindings::bindings::Gecko_GetProgressFromComputedTiming;
624
625 let property = match LonghandId::from_nscsspropertyid(css_property) {
626 Ok(longhand) if longhand.is_animatable() => longhand,
627 _ => return,
628 };
629 let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
630
631 // We will need an underlying value if either of the endpoints is null...
632 let need_underlying_value = segment.mFromValue.mServo.mRawPtr.is_null() ||
633 segment.mToValue.mServo.mRawPtr.is_null() ||
634 // ... or if they have a non-replace composite mode ...
635 segment.mFromComposite != CompositeOperation::Replace ||
636 segment.mToComposite != CompositeOperation::Replace ||
637 // ... or if we accumulate onto the last value and it is null.
638 (iteration_composite == IterationCompositeOperation::Accumulate &&
639 computed_timing.mCurrentIteration > 0 &&
640 last_segment.mToValue.mServo.mRawPtr.is_null());
641
642 // If either of the segment endpoints are null, get the underlying value to
643 // use from the current value in the values map (set by a lower-priority
644 // effect), or, if there is no current value, look up the cached base value
645 // for this property.
646 let underlying_value = if need_underlying_value {
647 let previous_composed_value = value_map.get(&property).cloned();
648 previous_composed_value.or_else(|| {
649 let raw_base_style =
650 unsafe { Gecko_AnimationGetBaseStyle(base_values, css_property).as_ref() };
651 AnimationValue::arc_from_borrowed(&raw_base_style)
652 .map(|v| &**v)
653 .cloned()
654 })
655 } else {
656 None
657 };
658
659 if need_underlying_value && underlying_value.is_none() {
660 warn!("Underlying value should be valid when we expect to use it");
661 return;
662 }
663
664 let raw_last_value;
665 let last_value = if !last_segment.mToValue.mServo.mRawPtr.is_null() {
666 raw_last_value = unsafe { &*last_segment.mToValue.mServo.mRawPtr };
667 Some(&**AnimationValue::as_arc(&raw_last_value))
668 } else {
669 None
670 };
671
672 let progress = unsafe { Gecko_GetProgressFromComputedTiming(computed_timing) };
673 let position = if segment.mToKey == segment.mFromKey {
674 // Note: compose_animation_segment doesn't use this value
675 // if segment.mFromKey == segment.mToKey, so assigning |progress| directly is fine.
676 progress
677 } else {
678 unsafe { Gecko_GetPositionInSegment(segment, progress, computed_timing.mBeforeFlag) }
679 };
680
681 let result = compose_animation_segment(
682 segment,
683 underlying_value.as_ref(),
684 last_value,
685 iteration_composite,
686 computed_timing.mCurrentIteration,
687 progress,
688 position,
689 );
690 value_map.insert(property, result);
691 }
692
693 macro_rules! get_property_id_from_nscsspropertyid {
694 ($property_id: ident, $ret: expr) => {{
695 match PropertyId::from_nscsspropertyid($property_id) {
696 Ok(property_id) => property_id,
697 Err(()) => {
698 return $ret;
699 },
700 }
701 }};
702 }
703
704 #[no_mangle]
Servo_AnimationValue_Serialize( value: &RawServoAnimationValue, property: nsCSSPropertyID, raw_data: &RawServoStyleSet, buffer: &mut nsAString, )705 pub extern "C" fn Servo_AnimationValue_Serialize(
706 value: &RawServoAnimationValue,
707 property: nsCSSPropertyID,
708 raw_data: &RawServoStyleSet,
709 buffer: &mut nsAString,
710 ) {
711 let uncomputed_value = AnimationValue::as_arc(&value).uncompute();
712 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
713 let rv = PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal)
714 .single_value_to_css(
715 &get_property_id_from_nscsspropertyid!(property, ()),
716 buffer,
717 None,
718 None, /* No extra custom properties */
719 &data.stylist.device(),
720 );
721 debug_assert!(rv.is_ok());
722 }
723
724 /// Debug: MOZ_DBG for AnimationValue.
725 #[no_mangle]
Servo_AnimationValue_Dump( value: &RawServoAnimationValue, result: &mut nsAString, )726 pub extern "C" fn Servo_AnimationValue_Dump(
727 value: &RawServoAnimationValue,
728 result: &mut nsAString,
729 ) {
730 let value = AnimationValue::as_arc(&value);
731 write!(result, "{:?}", value).unwrap();
732 }
733
734 #[no_mangle]
Servo_AnimationValue_GetColor( value: &RawServoAnimationValue, foreground_color: structs::nscolor, ) -> structs::nscolor735 pub extern "C" fn Servo_AnimationValue_GetColor(
736 value: &RawServoAnimationValue,
737 foreground_color: structs::nscolor,
738 ) -> structs::nscolor {
739 use style::gecko::values::convert_nscolor_to_rgba;
740 use style::gecko::values::convert_rgba_to_nscolor;
741 use style::values::animated::ToAnimatedValue;
742 use style::values::computed::color::Color as ComputedColor;
743
744 let value = AnimationValue::as_arc(&value);
745 match **value {
746 AnimationValue::BackgroundColor(color) => {
747 let computed: ComputedColor = ToAnimatedValue::from_animated_value(color);
748 let foreground_color = convert_nscolor_to_rgba(foreground_color);
749 convert_rgba_to_nscolor(&computed.to_rgba(foreground_color))
750 },
751 _ => panic!("Other color properties are not supported yet"),
752 }
753 }
754
755 #[no_mangle]
Servo_AnimationValue_IsCurrentColor( value: &RawServoAnimationValue, ) -> bool756 pub extern "C" fn Servo_AnimationValue_IsCurrentColor(
757 value: &RawServoAnimationValue,
758 ) -> bool {
759 let value = AnimationValue::as_arc(&value);
760 match **value {
761 AnimationValue::BackgroundColor(color) => {
762 color.is_currentcolor()
763 },
764 _ => {
765 debug_assert!(false, "Other color properties are not supported yet");
766 false
767 },
768 }
769 }
770
771 #[no_mangle]
Servo_AnimationValue_GetOpacity(value: &RawServoAnimationValue) -> f32772 pub extern "C" fn Servo_AnimationValue_GetOpacity(value: &RawServoAnimationValue) -> f32 {
773 let value = AnimationValue::as_arc(&value);
774 if let AnimationValue::Opacity(opacity) = **value {
775 opacity
776 } else {
777 panic!("The AnimationValue should be Opacity");
778 }
779 }
780
781 #[no_mangle]
Servo_AnimationValue_Opacity(opacity: f32) -> Strong<RawServoAnimationValue>782 pub extern "C" fn Servo_AnimationValue_Opacity(opacity: f32) -> Strong<RawServoAnimationValue> {
783 Arc::new(AnimationValue::Opacity(opacity)).into_strong()
784 }
785
786 #[no_mangle]
Servo_AnimationValue_Color( color_property: nsCSSPropertyID, color: structs::nscolor, ) -> Strong<RawServoAnimationValue>787 pub extern "C" fn Servo_AnimationValue_Color(
788 color_property: nsCSSPropertyID,
789 color: structs::nscolor,
790 ) -> Strong<RawServoAnimationValue> {
791 use style::gecko::values::convert_nscolor_to_rgba;
792 use style::values::animated::color::RGBA as AnimatedRGBA;
793
794 let property = LonghandId::from_nscsspropertyid(color_property)
795 .expect("We don't have shorthand property animation value");
796
797 let rgba = convert_nscolor_to_rgba(color);
798
799 let animatedRGBA = AnimatedRGBA::new(
800 rgba.red_f32(),
801 rgba.green_f32(),
802 rgba.blue_f32(),
803 rgba.alpha_f32(),
804 );
805 match property {
806 LonghandId::BackgroundColor => {
807 Arc::new(AnimationValue::BackgroundColor(animatedRGBA.into())).into_strong()
808 },
809 _ => panic!("Should be background-color property"),
810 }
811 }
812
813 #[no_mangle]
Servo_AnimationValue_GetScale( value: &RawServoAnimationValue, ) -> *const computed::Scale814 pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
815 value: &RawServoAnimationValue,
816 ) -> *const computed::Scale {
817 let value = AnimationValue::as_arc(&value);
818 match **value {
819 AnimationValue::Scale(ref value) => value,
820 _ => unreachable!("Expected scale"),
821 }
822 }
823
824 #[no_mangle]
Servo_AnimationValue_GetTranslate( value: &RawServoAnimationValue, ) -> *const computed::Translate825 pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
826 value: &RawServoAnimationValue,
827 ) -> *const computed::Translate {
828 let value = AnimationValue::as_arc(&value);
829 match **value {
830 AnimationValue::Translate(ref value) => value,
831 _ => unreachable!("Expected translate"),
832 }
833 }
834
835 #[no_mangle]
Servo_AnimationValue_GetRotate( value: &RawServoAnimationValue, ) -> *const computed::Rotate836 pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
837 value: &RawServoAnimationValue,
838 ) -> *const computed::Rotate {
839 let value = AnimationValue::as_arc(&value);
840 match **value {
841 AnimationValue::Rotate(ref value) => value,
842 _ => unreachable!("Expected rotate"),
843 }
844 }
845
846 #[no_mangle]
Servo_AnimationValue_GetTransform( value: &RawServoAnimationValue, ) -> *const computed::Transform847 pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
848 value: &RawServoAnimationValue,
849 ) -> *const computed::Transform {
850 let value = AnimationValue::as_arc(&value);
851 match **value {
852 AnimationValue::Transform(ref value) => value,
853 _ => unreachable!("Unsupported transform animation value"),
854 }
855 }
856
857 #[no_mangle]
Servo_AnimationValue_GetOffsetPath( value: &RawServoAnimationValue, ) -> *const computed::motion::OffsetPath858 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
859 value: &RawServoAnimationValue,
860 ) -> *const computed::motion::OffsetPath {
861 let value = AnimationValue::as_arc(&value);
862 match **value {
863 AnimationValue::OffsetPath(ref value) => value,
864 _ => unreachable!("Expected offset-path"),
865 }
866 }
867
868 #[no_mangle]
Servo_AnimationValue_GetOffsetDistance( value: &RawServoAnimationValue, ) -> *const computed::LengthPercentage869 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetDistance(
870 value: &RawServoAnimationValue,
871 ) -> *const computed::LengthPercentage {
872 let value = AnimationValue::as_arc(&value);
873 match **value {
874 AnimationValue::OffsetDistance(ref value) => value,
875 _ => unreachable!("Expected offset-distance"),
876 }
877 }
878
879 #[no_mangle]
Servo_AnimationValue_GetOffsetRotate( value: &RawServoAnimationValue, ) -> *const computed::motion::OffsetRotate880 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetRotate(
881 value: &RawServoAnimationValue,
882 ) -> *const computed::motion::OffsetRotate {
883 let value = AnimationValue::as_arc(&value);
884 match **value {
885 AnimationValue::OffsetRotate(ref value) => value,
886 _ => unreachable!("Expected offset-rotate"),
887 }
888 }
889
890 #[no_mangle]
Servo_AnimationValue_GetOffsetAnchor( value: &RawServoAnimationValue, ) -> *const computed::position::PositionOrAuto891 pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetAnchor(
892 value: &RawServoAnimationValue,
893 ) -> *const computed::position::PositionOrAuto {
894 let value = AnimationValue::as_arc(&value);
895 match **value {
896 AnimationValue::OffsetAnchor(ref value) => value,
897 _ => unreachable!("Expected offset-anchor"),
898 }
899 }
900
901 #[no_mangle]
Servo_AnimationValue_Rotate( r: &computed::Rotate, ) -> Strong<RawServoAnimationValue>902 pub unsafe extern "C" fn Servo_AnimationValue_Rotate(
903 r: &computed::Rotate,
904 ) -> Strong<RawServoAnimationValue> {
905 Arc::new(AnimationValue::Rotate(r.clone())).into_strong()
906 }
907
908 #[no_mangle]
Servo_AnimationValue_Translate( t: &computed::Translate, ) -> Strong<RawServoAnimationValue>909 pub unsafe extern "C" fn Servo_AnimationValue_Translate(
910 t: &computed::Translate,
911 ) -> Strong<RawServoAnimationValue> {
912 Arc::new(AnimationValue::Translate(t.clone())).into_strong()
913 }
914
915 #[no_mangle]
Servo_AnimationValue_Scale( s: &computed::Scale, ) -> Strong<RawServoAnimationValue>916 pub unsafe extern "C" fn Servo_AnimationValue_Scale(
917 s: &computed::Scale,
918 ) -> Strong<RawServoAnimationValue> {
919 Arc::new(AnimationValue::Scale(s.clone())).into_strong()
920 }
921
922 #[no_mangle]
Servo_AnimationValue_Transform( transform: &computed::Transform, ) -> Strong<RawServoAnimationValue>923 pub unsafe extern "C" fn Servo_AnimationValue_Transform(
924 transform: &computed::Transform,
925 ) -> Strong<RawServoAnimationValue> {
926 Arc::new(AnimationValue::Transform(transform.clone())).into_strong()
927 }
928
929 #[no_mangle]
Servo_AnimationValue_OffsetPath( p: &computed::motion::OffsetPath, ) -> Strong<RawServoAnimationValue>930 pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
931 p: &computed::motion::OffsetPath,
932 ) -> Strong<RawServoAnimationValue> {
933 Arc::new(AnimationValue::OffsetPath(p.clone())).into_strong()
934 }
935
936 #[no_mangle]
Servo_AnimationValue_OffsetDistance( d: &computed::length::LengthPercentage, ) -> Strong<RawServoAnimationValue>937 pub unsafe extern "C" fn Servo_AnimationValue_OffsetDistance(
938 d: &computed::length::LengthPercentage,
939 ) -> Strong<RawServoAnimationValue> {
940 Arc::new(AnimationValue::OffsetDistance(d.clone())).into_strong()
941 }
942
943 #[no_mangle]
Servo_AnimationValue_OffsetRotate( r: &computed::motion::OffsetRotate, ) -> Strong<RawServoAnimationValue>944 pub unsafe extern "C" fn Servo_AnimationValue_OffsetRotate(
945 r: &computed::motion::OffsetRotate,
946 ) -> Strong<RawServoAnimationValue> {
947 Arc::new(AnimationValue::OffsetRotate(*r)).into_strong()
948 }
949
950 #[no_mangle]
Servo_AnimationValue_OffsetAnchor( p: &computed::position::PositionOrAuto, ) -> Strong<RawServoAnimationValue>951 pub unsafe extern "C" fn Servo_AnimationValue_OffsetAnchor(
952 p: &computed::position::PositionOrAuto,
953 ) -> Strong<RawServoAnimationValue> {
954 Arc::new(AnimationValue::OffsetAnchor(p.clone())).into_strong()
955 }
956
957 #[no_mangle]
Servo_AnimationValue_DeepEqual( this: &RawServoAnimationValue, other: &RawServoAnimationValue, ) -> bool958 pub extern "C" fn Servo_AnimationValue_DeepEqual(
959 this: &RawServoAnimationValue,
960 other: &RawServoAnimationValue,
961 ) -> bool {
962 let this_value = AnimationValue::as_arc(&this);
963 let other_value = AnimationValue::as_arc(&other);
964 this_value == other_value
965 }
966
967 #[no_mangle]
Servo_AnimationValue_Uncompute( value: &RawServoAnimationValue, ) -> Strong<RawServoDeclarationBlock>968 pub extern "C" fn Servo_AnimationValue_Uncompute(
969 value: &RawServoAnimationValue,
970 ) -> Strong<RawServoDeclarationBlock> {
971 let value = AnimationValue::as_arc(&value);
972 let global_style_data = &*GLOBAL_STYLE_DATA;
973 Arc::new(
974 global_style_data
975 .shared_lock
976 .wrap(PropertyDeclarationBlock::with_one(
977 value.uncompute(),
978 Importance::Normal,
979 )),
980 )
981 .into_strong()
982 }
983
984 #[inline]
create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf985 fn create_byte_buf_from_vec(mut v: Vec<u8>) -> ByteBuf {
986 let w = ByteBuf {
987 mData: v.as_mut_ptr(),
988 mLen: v.len(),
989 mCapacity: v.capacity(),
990 };
991 std::mem::forget(v);
992 w
993 }
994
995 #[inline]
view_byte_buf(b: &ByteBuf) -> &[u8]996 fn view_byte_buf(b: &ByteBuf) -> &[u8] {
997 if b.mData.is_null() {
998 debug_assert_eq!(b.mCapacity, 0);
999 return &[];
1000 }
1001 unsafe { std::slice::from_raw_parts(b.mData, b.mLen) }
1002 }
1003
1004 macro_rules! impl_basic_serde_funcs {
1005 ($ser_name:ident, $de_name:ident, $computed_type:ty) => {
1006 #[no_mangle]
1007 pub extern "C" fn $ser_name(v: &$computed_type, output: &mut ByteBuf) -> bool {
1008 let buf = match serialize(v) {
1009 Ok(buf) => buf,
1010 Err(..) => return false,
1011 };
1012
1013 *output = create_byte_buf_from_vec(buf);
1014 true
1015 }
1016
1017 #[no_mangle]
1018 pub extern "C" fn $de_name(input: &ByteBuf, v: &mut $computed_type) -> bool {
1019 let buf = match deserialize(view_byte_buf(input)) {
1020 Ok(buf) => buf,
1021 Err(..) => return false,
1022 };
1023
1024 *v = buf;
1025 true
1026 }
1027 };
1028 }
1029
1030 impl_basic_serde_funcs!(
1031 Servo_LengthPercentage_Serialize,
1032 Servo_LengthPercentage_Deserialize,
1033 computed::LengthPercentage
1034 );
1035
1036 impl_basic_serde_funcs!(
1037 Servo_StyleRotate_Serialize,
1038 Servo_StyleRotate_Deserialize,
1039 computed::transform::Rotate
1040 );
1041
1042 impl_basic_serde_funcs!(
1043 Servo_StyleScale_Serialize,
1044 Servo_StyleScale_Deserialize,
1045 computed::transform::Scale
1046 );
1047
1048 impl_basic_serde_funcs!(
1049 Servo_StyleTranslate_Serialize,
1050 Servo_StyleTranslate_Deserialize,
1051 computed::transform::Translate
1052 );
1053
1054 impl_basic_serde_funcs!(
1055 Servo_StyleTransform_Serialize,
1056 Servo_StyleTransform_Deserialize,
1057 computed::transform::Transform
1058 );
1059
1060 impl_basic_serde_funcs!(
1061 Servo_StyleOffsetPath_Serialize,
1062 Servo_StyleOffsetPath_Deserialize,
1063 computed::motion::OffsetPath
1064 );
1065
1066 impl_basic_serde_funcs!(
1067 Servo_StyleOffsetRotate_Serialize,
1068 Servo_StyleOffsetRotate_Deserialize,
1069 computed::motion::OffsetRotate
1070 );
1071
1072 impl_basic_serde_funcs!(
1073 Servo_StylePositionOrAuto_Serialize,
1074 Servo_StylePositionOrAuto_Deserialize,
1075 computed::position::PositionOrAuto
1076 );
1077
1078 #[no_mangle]
Servo_SVGPathData_Normalize( input: &specified::SVGPathData, output: &mut specified::SVGPathData, )1079 pub extern "C" fn Servo_SVGPathData_Normalize(
1080 input: &specified::SVGPathData,
1081 output: &mut specified::SVGPathData,
1082 ) {
1083 *output = input.normalize();
1084 }
1085
1086 // Return the ComputedValues by a base ComputedValues and the rules.
resolve_rules_for_element_with_context<'a>( element: GeckoElement<'a>, mut context: StyleContext<GeckoElement<'a>>, rules: StrongRuleNode, ) -> Arc<ComputedValues>1087 fn resolve_rules_for_element_with_context<'a>(
1088 element: GeckoElement<'a>,
1089 mut context: StyleContext<GeckoElement<'a>>,
1090 rules: StrongRuleNode,
1091 ) -> Arc<ComputedValues> {
1092 use style::style_resolver::{PseudoElementResolution, StyleResolverForElement};
1093
1094 // This currently ignores visited styles, which seems acceptable, as
1095 // existing browsers don't appear to animate visited styles.
1096 let inputs = CascadeInputs {
1097 rules: Some(rules),
1098 visited_rules: None,
1099 };
1100
1101 // Actually `PseudoElementResolution` doesn't matter.
1102 let mut resolver = StyleResolverForElement::new(
1103 element,
1104 &mut context,
1105 RuleInclusion::All,
1106 PseudoElementResolution::IfApplicable,
1107 );
1108 resolver
1109 .cascade_style_and_visited_with_default_parents(inputs)
1110 .0
1111 }
1112
1113 #[no_mangle]
Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap>1114 pub extern "C" fn Servo_AnimationValueMap_Create() -> Owned<structs::RawServoAnimationValueMap> {
1115 Box::<AnimationValueMap>::default().into_ffi()
1116 }
1117
1118 #[no_mangle]
Servo_AnimationValueMap_Drop( value_map: *mut structs::RawServoAnimationValueMap, )1119 pub unsafe extern "C" fn Servo_AnimationValueMap_Drop(
1120 value_map: *mut structs::RawServoAnimationValueMap,
1121 ) {
1122 AnimationValueMap::drop_ffi(value_map)
1123 }
1124
1125 #[no_mangle]
Servo_AnimationValueMap_GetValue( raw_value_map: &mut structs::RawServoAnimationValueMap, property_id: nsCSSPropertyID, ) -> Strong<RawServoAnimationValue>1126 pub extern "C" fn Servo_AnimationValueMap_GetValue(
1127 raw_value_map: &mut structs::RawServoAnimationValueMap,
1128 property_id: nsCSSPropertyID,
1129 ) -> Strong<RawServoAnimationValue> {
1130 let property = match LonghandId::from_nscsspropertyid(property_id) {
1131 Ok(longhand) => longhand,
1132 Err(()) => return Strong::null(),
1133 };
1134 let value_map = AnimationValueMap::from_ffi_mut(raw_value_map);
1135
1136 value_map.get(&property).map_or(Strong::null(), |value| {
1137 Arc::new(value.clone()).into_strong()
1138 })
1139 }
1140
1141 #[no_mangle]
Servo_StyleSet_GetBaseComputedValuesForElement( raw_style_set: &RawServoStyleSet, element: &RawGeckoElement, computed_values: &ComputedValues, snapshots: *const ServoElementSnapshotTable, ) -> Strong<ComputedValues>1142 pub extern "C" fn Servo_StyleSet_GetBaseComputedValuesForElement(
1143 raw_style_set: &RawServoStyleSet,
1144 element: &RawGeckoElement,
1145 computed_values: &ComputedValues,
1146 snapshots: *const ServoElementSnapshotTable,
1147 ) -> Strong<ComputedValues> {
1148 debug_assert!(!snapshots.is_null());
1149 let computed_values = unsafe { ArcBorrow::from_ref(computed_values) };
1150
1151 let rules = match computed_values.rules {
1152 None => return computed_values.clone_arc().into(),
1153 Some(ref rules) => rules,
1154 };
1155
1156 let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
1157 let without_animations_rules = doc_data.stylist.rule_tree().remove_animation_rules(rules);
1158 if without_animations_rules == *rules {
1159 return computed_values.clone_arc().into();
1160 }
1161
1162 let element = GeckoElement(element);
1163
1164 let global_style_data = &*GLOBAL_STYLE_DATA;
1165 let guard = global_style_data.shared_lock.read();
1166 let shared = create_shared_context(
1167 &global_style_data,
1168 &guard,
1169 &doc_data,
1170 TraversalFlags::empty(),
1171 unsafe { &*snapshots },
1172 );
1173 let mut tlc = ThreadLocalStyleContext::new(&shared);
1174 let context = StyleContext {
1175 shared: &shared,
1176 thread_local: &mut tlc,
1177 };
1178
1179 resolve_rules_for_element_with_context(element, context, without_animations_rules).into()
1180 }
1181
1182 #[no_mangle]
Servo_StyleSet_GetComputedValuesByAddingAnimation( raw_style_set: &RawServoStyleSet, element: &RawGeckoElement, computed_values: &ComputedValues, snapshots: *const ServoElementSnapshotTable, animation_value: &RawServoAnimationValue, ) -> Strong<ComputedValues>1183 pub extern "C" fn Servo_StyleSet_GetComputedValuesByAddingAnimation(
1184 raw_style_set: &RawServoStyleSet,
1185 element: &RawGeckoElement,
1186 computed_values: &ComputedValues,
1187 snapshots: *const ServoElementSnapshotTable,
1188 animation_value: &RawServoAnimationValue,
1189 ) -> Strong<ComputedValues> {
1190 debug_assert!(!snapshots.is_null());
1191 let rules = match computed_values.rules {
1192 None => return Strong::null(),
1193 Some(ref rules) => rules,
1194 };
1195
1196 let global_style_data = &*GLOBAL_STYLE_DATA;
1197 let guard = global_style_data.shared_lock.read();
1198 let uncomputed_value = AnimationValue::as_arc(&animation_value).uncompute();
1199 let doc_data = PerDocumentStyleData::from_ffi(raw_style_set).borrow();
1200
1201 let with_animations_rules = {
1202 let guards = StylesheetGuards::same(&guard);
1203 let declarations = Arc::new(global_style_data.shared_lock.wrap(
1204 PropertyDeclarationBlock::with_one(uncomputed_value, Importance::Normal),
1205 ));
1206 doc_data
1207 .stylist
1208 .rule_tree()
1209 .add_animation_rules_at_transition_level(rules, declarations, &guards)
1210 };
1211
1212 let element = GeckoElement(element);
1213 if element.borrow_data().is_none() {
1214 return Strong::null();
1215 }
1216
1217 let shared = create_shared_context(
1218 &global_style_data,
1219 &guard,
1220 &doc_data,
1221 TraversalFlags::empty(),
1222 unsafe { &*snapshots },
1223 );
1224 let mut tlc: ThreadLocalStyleContext<GeckoElement> = ThreadLocalStyleContext::new(&shared);
1225 let context = StyleContext {
1226 shared: &shared,
1227 thread_local: &mut tlc,
1228 };
1229
1230 resolve_rules_for_element_with_context(element, context, with_animations_rules).into()
1231 }
1232
1233 #[no_mangle]
Servo_ComputedValues_ExtractAnimationValue( computed_values: &ComputedValues, property_id: nsCSSPropertyID, ) -> Strong<RawServoAnimationValue>1234 pub extern "C" fn Servo_ComputedValues_ExtractAnimationValue(
1235 computed_values: &ComputedValues,
1236 property_id: nsCSSPropertyID,
1237 ) -> Strong<RawServoAnimationValue> {
1238 let property = match LonghandId::from_nscsspropertyid(property_id) {
1239 Ok(longhand) => longhand,
1240 Err(()) => return Strong::null(),
1241 };
1242 match AnimationValue::from_computed_values(property, &computed_values) {
1243 Some(v) => Arc::new(v).into_strong(),
1244 None => Strong::null(),
1245 }
1246 }
1247
1248 #[no_mangle]
Servo_ResolveLogicalProperty( property_id: nsCSSPropertyID, style: &ComputedValues, ) -> nsCSSPropertyID1249 pub extern "C" fn Servo_ResolveLogicalProperty(
1250 property_id: nsCSSPropertyID,
1251 style: &ComputedValues,
1252 ) -> nsCSSPropertyID {
1253 let longhand = LonghandId::from_nscsspropertyid(property_id)
1254 .expect("We shouldn't need to care about shorthands");
1255
1256 longhand
1257 .to_physical(style.writing_mode)
1258 .to_nscsspropertyid()
1259 }
1260
1261 #[no_mangle]
Servo_Property_LookupEnabledForAllContent( prop: &nsACString, ) -> nsCSSPropertyID1262 pub unsafe extern "C" fn Servo_Property_LookupEnabledForAllContent(
1263 prop: &nsACString,
1264 ) -> nsCSSPropertyID {
1265 match PropertyId::parse_enabled_for_all_content(prop.as_str_unchecked()) {
1266 Ok(p) => p.to_nscsspropertyid_resolving_aliases(),
1267 Err(..) => nsCSSPropertyID::eCSSProperty_UNKNOWN,
1268 }
1269 }
1270
1271 #[no_mangle]
Servo_Property_GetName( prop: nsCSSPropertyID, out_length: *mut u32, ) -> *const u81272 pub unsafe extern "C" fn Servo_Property_GetName(
1273 prop: nsCSSPropertyID,
1274 out_length: *mut u32,
1275 ) -> *const u8 {
1276 let (ptr, len) = match NonCustomPropertyId::from_nscsspropertyid(prop) {
1277 Ok(p) => {
1278 let name = p.name();
1279 (name.as_bytes().as_ptr(), name.len())
1280 },
1281 Err(..) => (ptr::null(), 0),
1282 };
1283
1284 *out_length = len as u32;
1285 ptr
1286 }
1287
1288 macro_rules! parse_enabled_property_name {
1289 ($prop_name:ident, $found:ident, $default:expr) => {{
1290 let prop_name = $prop_name.as_str_unchecked();
1291 match PropertyId::parse_enabled_for_all_content(prop_name) {
1292 Ok(p) => {
1293 *$found = true;
1294 p
1295 },
1296 Err(..) => {
1297 *$found = false;
1298 return $default;
1299 },
1300 }
1301 }};
1302 }
1303
1304 #[no_mangle]
Servo_Property_IsShorthand( prop_name: &nsACString, found: *mut bool, ) -> bool1305 pub unsafe extern "C" fn Servo_Property_IsShorthand(
1306 prop_name: &nsACString,
1307 found: *mut bool,
1308 ) -> bool {
1309 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1310 prop_id.is_shorthand()
1311 }
1312
1313 #[no_mangle]
Servo_Property_IsInherited(prop_name: &nsACString) -> bool1314 pub unsafe extern "C" fn Servo_Property_IsInherited(prop_name: &nsACString) -> bool {
1315 let prop_name = prop_name.as_str_unchecked();
1316 let prop_id = match PropertyId::parse_enabled_for_all_content(prop_name) {
1317 Ok(id) => id,
1318 Err(_) => return false,
1319 };
1320 let longhand_id = match prop_id {
1321 PropertyId::Custom(_) => return true,
1322 PropertyId::Longhand(id) | PropertyId::LonghandAlias(id, _) => id,
1323 PropertyId::Shorthand(id) | PropertyId::ShorthandAlias(id, _) => {
1324 id.longhands().next().unwrap()
1325 },
1326 };
1327 longhand_id.inherited()
1328 }
1329
1330 #[no_mangle]
Servo_Property_SupportsType( prop_name: &nsACString, ty: u8, found: *mut bool, ) -> bool1331 pub unsafe extern "C" fn Servo_Property_SupportsType(
1332 prop_name: &nsACString,
1333 ty: u8,
1334 found: *mut bool,
1335 ) -> bool {
1336 let prop_id = parse_enabled_property_name!(prop_name, found, false);
1337 prop_id.supports_type(ty)
1338 }
1339
1340 // TODO(emilio): We could use ThinVec instead of nsTArray.
1341 #[no_mangle]
Servo_Property_GetCSSValuesForProperty( prop_name: &nsACString, found: *mut bool, result: &mut nsTArray<nsString>, )1342 pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
1343 prop_name: &nsACString,
1344 found: *mut bool,
1345 result: &mut nsTArray<nsString>,
1346 ) {
1347 let prop_id = parse_enabled_property_name!(prop_name, found, ());
1348 // Use B-tree set for unique and sorted result.
1349 let mut values = BTreeSet::<&'static str>::new();
1350 prop_id.collect_property_completion_keywords(&mut |list| values.extend(list.iter()));
1351
1352 let mut extras = vec![];
1353 if values.contains("transparent") {
1354 // This is a special value devtools use to avoid inserting the
1355 // long list of color keywords. We need to prepend it to values.
1356 extras.push("COLOR");
1357 }
1358
1359 let len = extras.len() + values.len();
1360 bindings::Gecko_ResizeTArrayForStrings(result, len as u32);
1361
1362 for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
1363 dest.write_str(src).unwrap();
1364 }
1365 }
1366
1367 #[no_mangle]
Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool1368 pub extern "C" fn Servo_Property_IsAnimatable(prop: nsCSSPropertyID) -> bool {
1369 NonCustomPropertyId::from_nscsspropertyid(prop)
1370 .ok()
1371 .map_or(false, |p| p.is_animatable())
1372 }
1373
1374 #[no_mangle]
Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool1375 pub extern "C" fn Servo_Property_IsTransitionable(prop: nsCSSPropertyID) -> bool {
1376 NonCustomPropertyId::from_nscsspropertyid(prop)
1377 .ok()
1378 .map_or(false, |p| p.is_transitionable())
1379 }
1380
1381 #[no_mangle]
Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool1382 pub extern "C" fn Servo_Property_IsDiscreteAnimatable(property: nsCSSPropertyID) -> bool {
1383 match LonghandId::from_nscsspropertyid(property) {
1384 Ok(longhand) => longhand.is_discrete_animatable(),
1385 Err(()) => return false,
1386 }
1387 }
1388
1389 #[no_mangle]
Servo_Element_ClearData(element: &RawGeckoElement)1390 pub extern "C" fn Servo_Element_ClearData(element: &RawGeckoElement) {
1391 unsafe { GeckoElement(element).clear_data() };
1392 }
1393
1394 #[no_mangle]
Servo_Element_SizeOfExcludingThisAndCVs( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, seen_ptrs: *mut SeenPtrs, element: &RawGeckoElement, ) -> usize1395 pub extern "C" fn Servo_Element_SizeOfExcludingThisAndCVs(
1396 malloc_size_of: GeckoMallocSizeOf,
1397 malloc_enclosing_size_of: GeckoMallocSizeOf,
1398 seen_ptrs: *mut SeenPtrs,
1399 element: &RawGeckoElement,
1400 ) -> usize {
1401 let element = GeckoElement(element);
1402 let borrow = element.borrow_data();
1403 if let Some(data) = borrow {
1404 let have_seen_ptr = move |ptr| unsafe { Gecko_HaveSeenPtr(seen_ptrs, ptr) };
1405 let mut ops = MallocSizeOfOps::new(
1406 malloc_size_of.unwrap(),
1407 Some(malloc_enclosing_size_of.unwrap()),
1408 Some(Box::new(have_seen_ptr)),
1409 );
1410 (*data).size_of_excluding_cvs(&mut ops)
1411 } else {
1412 0
1413 }
1414 }
1415
1416 #[no_mangle]
Servo_Element_GetMaybeOutOfDateStyle( element: &RawGeckoElement, ) -> *const ComputedValues1417 pub extern "C" fn Servo_Element_GetMaybeOutOfDateStyle(
1418 element: &RawGeckoElement,
1419 ) -> *const ComputedValues {
1420 let element = GeckoElement(element);
1421 let data = match element.borrow_data() {
1422 Some(d) => d,
1423 None => return ptr::null(),
1424 };
1425 &**data.styles.primary() as *const _
1426 }
1427
1428 #[no_mangle]
Servo_Element_GetMaybeOutOfDatePseudoStyle( element: &RawGeckoElement, index: usize, ) -> *const ComputedValues1429 pub extern "C" fn Servo_Element_GetMaybeOutOfDatePseudoStyle(
1430 element: &RawGeckoElement,
1431 index: usize,
1432 ) -> *const ComputedValues {
1433 let element = GeckoElement(element);
1434 let data = match element.borrow_data() {
1435 Some(d) => d,
1436 None => return ptr::null(),
1437 };
1438 match data.styles.pseudos.as_array()[index].as_ref() {
1439 Some(style) => &**style as *const _,
1440 None => ptr::null(),
1441 }
1442 }
1443
1444 #[no_mangle]
Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool1445 pub extern "C" fn Servo_Element_IsDisplayNone(element: &RawGeckoElement) -> bool {
1446 let element = GeckoElement(element);
1447 let data = element
1448 .get_data()
1449 .expect("Invoking Servo_Element_IsDisplayNone on unstyled element");
1450
1451 // This function is hot, so we bypass the AtomicRefCell.
1452 //
1453 // It would be nice to also assert that we're not in the servo traversal,
1454 // but this function is called at various intermediate checkpoints when
1455 // managing the traversal on the Gecko side.
1456 debug_assert!(is_main_thread());
1457 unsafe { &*data.as_ptr() }.styles.is_display_none()
1458 }
1459
1460 #[no_mangle]
Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool1461 pub extern "C" fn Servo_Element_IsDisplayContents(element: &RawGeckoElement) -> bool {
1462 let element = GeckoElement(element);
1463 let data = element
1464 .get_data()
1465 .expect("Invoking Servo_Element_IsDisplayContents on unstyled element");
1466
1467 debug_assert!(is_main_thread());
1468 unsafe { &*data.as_ptr() }
1469 .styles
1470 .primary()
1471 .get_box()
1472 .clone_display()
1473 .is_contents()
1474 }
1475
1476 #[no_mangle]
Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool1477 pub extern "C" fn Servo_Element_IsPrimaryStyleReusedViaRuleNode(element: &RawGeckoElement) -> bool {
1478 let element = GeckoElement(element);
1479 let data = element
1480 .borrow_data()
1481 .expect("Invoking Servo_Element_IsPrimaryStyleReusedViaRuleNode on unstyled element");
1482 data.flags
1483 .contains(data::ElementDataFlags::PRIMARY_STYLE_REUSED_VIA_RULE_NODE)
1484 }
1485
mode_to_origin(mode: SheetParsingMode) -> Origin1486 fn mode_to_origin(mode: SheetParsingMode) -> Origin {
1487 match mode {
1488 SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
1489 SheetParsingMode::eUserSheetFeatures => Origin::User,
1490 SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
1491 }
1492 }
1493
1494 #[no_mangle]
Servo_StyleSheet_Empty( mode: SheetParsingMode, ) -> Strong<RawServoStyleSheetContents>1495 pub extern "C" fn Servo_StyleSheet_Empty(
1496 mode: SheetParsingMode,
1497 ) -> Strong<RawServoStyleSheetContents> {
1498 let global_style_data = &*GLOBAL_STYLE_DATA;
1499 let origin = mode_to_origin(mode);
1500 let shared_lock = &global_style_data.shared_lock;
1501 Arc::new(StylesheetContents::from_str(
1502 "",
1503 unsafe { dummy_url_data() }.clone(),
1504 origin,
1505 shared_lock,
1506 /* loader = */ None,
1507 None,
1508 QuirksMode::NoQuirks,
1509 0,
1510 /* use_counters = */ None,
1511 AllowImportRules::Yes,
1512 /* sanitization_data = */ None,
1513 ))
1514 .into_strong()
1515 }
1516
1517 /// Note: The load_data corresponds to this sheet, and is passed as the parent
1518 /// load data for child sheet loads. It may be null for certain cases where we
1519 /// know we won't have child loads.
1520 #[no_mangle]
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>1521 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
1522 loader: *mut Loader,
1523 stylesheet: *mut DomStyleSheet,
1524 load_data: *mut SheetLoadData,
1525 bytes: &nsACString,
1526 mode: SheetParsingMode,
1527 extra_data: *mut URLExtraData,
1528 line_number_offset: u32,
1529 quirks_mode: nsCompatibility,
1530 reusable_sheets: *mut LoaderReusableStyleSheets,
1531 use_counters: Option<&UseCounters>,
1532 allow_import_rules: AllowImportRules,
1533 sanitization_kind: SanitizationKind,
1534 sanitized_output: Option<&mut nsAString>,
1535 ) -> Strong<RawServoStyleSheetContents> {
1536 let global_style_data = &*GLOBAL_STYLE_DATA;
1537 let input = bytes.as_str_unchecked();
1538
1539 let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
1540 let url_data = UrlExtraData::from_ptr_ref(&extra_data);
1541 let loader = if loader.is_null() {
1542 None
1543 } else {
1544 debug_assert!(
1545 sanitized_output.is_none(),
1546 "Shouldn't trigger @import loads for sanitization",
1547 );
1548 Some(StylesheetLoader::new(
1549 loader,
1550 stylesheet,
1551 load_data,
1552 reusable_sheets,
1553 ))
1554 };
1555
1556 // FIXME(emilio): loader.as_ref() doesn't typecheck for some reason?
1557 let loader: Option<&dyn StyleStylesheetLoader> = match loader {
1558 None => None,
1559 Some(ref s) => Some(s),
1560 };
1561
1562 let mut sanitization_data = SanitizationData::new(sanitization_kind);
1563
1564 let contents = Arc::new(StylesheetContents::from_str(
1565 input,
1566 url_data.clone(),
1567 mode_to_origin(mode),
1568 &global_style_data.shared_lock,
1569 loader,
1570 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
1571 quirks_mode.into(),
1572 line_number_offset,
1573 use_counters,
1574 allow_import_rules,
1575 sanitization_data.as_mut(),
1576 ));
1577
1578 if let Some(data) = sanitization_data {
1579 sanitized_output.unwrap().assign_utf8(data.take().as_bytes());
1580 }
1581
1582 contents.into_strong()
1583 }
1584
1585 #[no_mangle]
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, )1586 pub unsafe extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
1587 load_data: *mut SheetLoadDataHolder,
1588 extra_data: *mut URLExtraData,
1589 bytes: &nsACString,
1590 mode: SheetParsingMode,
1591 line_number_offset: u32,
1592 quirks_mode: nsCompatibility,
1593 should_record_use_counters: bool,
1594 allow_import_rules: AllowImportRules,
1595 ) {
1596 let load_data = RefPtr::new(load_data);
1597 let extra_data = UrlExtraData::new(extra_data);
1598
1599 let mut sheet_bytes = nsCString::new();
1600 sheet_bytes.assign(bytes);
1601
1602 let async_parser = AsyncStylesheetParser::new(
1603 load_data,
1604 extra_data,
1605 sheet_bytes,
1606 mode_to_origin(mode),
1607 quirks_mode.into(),
1608 line_number_offset,
1609 should_record_use_counters,
1610 allow_import_rules,
1611 );
1612
1613 if let Some(thread_pool) = STYLE_THREAD_POOL.pool().as_ref() {
1614 thread_pool.spawn(|| {
1615 profiler_label!(Parse);
1616 async_parser.parse();
1617 });
1618 } else {
1619 async_parser.parse();
1620 }
1621 }
1622
1623 #[no_mangle]
Servo_ShutdownThreadPool()1624 pub unsafe extern "C" fn Servo_ShutdownThreadPool() {
1625 debug_assert!(is_main_thread() && !is_in_servo_traversal());
1626 StyleThreadPool::shutdown();
1627 }
1628
1629 #[no_mangle]
Servo_StyleSheet_FromSharedData( extra_data: *mut URLExtraData, shared_rules: &ServoCssRules, ) -> Strong<RawServoStyleSheetContents>1630 pub unsafe extern "C" fn Servo_StyleSheet_FromSharedData(
1631 extra_data: *mut URLExtraData,
1632 shared_rules: &ServoCssRules,
1633 ) -> Strong<RawServoStyleSheetContents> {
1634 let shared_rules = Locked::<CssRules>::as_arc(&shared_rules);
1635 Arc::new(StylesheetContents::from_shared_data(
1636 shared_rules.clone_arc(),
1637 Origin::UserAgent,
1638 UrlExtraData::new(extra_data),
1639 QuirksMode::NoQuirks,
1640 ))
1641 .into_strong()
1642 }
1643
1644 #[no_mangle]
Servo_StyleSet_AppendStyleSheet( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, )1645 pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
1646 raw_data: &RawServoStyleSet,
1647 sheet: *const DomStyleSheet,
1648 ) {
1649 let global_style_data = &*GLOBAL_STYLE_DATA;
1650 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1651 let data = &mut *data;
1652 let guard = global_style_data.shared_lock.read();
1653 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1654 data.stylist.append_stylesheet(sheet, &guard);
1655 }
1656
1657 #[no_mangle]
Servo_AuthorStyles_Create() -> Owned<RawServoAuthorStyles>1658 pub extern "C" fn Servo_AuthorStyles_Create() -> Owned<RawServoAuthorStyles> {
1659 Box::new(AuthorStyles::<GeckoStyleSheet>::new()).into_ffi()
1660 }
1661
1662 #[no_mangle]
Servo_AuthorStyles_Drop(styles: *mut RawServoAuthorStyles)1663 pub unsafe extern "C" fn Servo_AuthorStyles_Drop(styles: *mut RawServoAuthorStyles) {
1664 AuthorStyles::drop_ffi(styles)
1665 }
1666
1667 #[no_mangle]
Servo_AuthorStyles_AppendStyleSheet( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, )1668 pub unsafe extern "C" fn Servo_AuthorStyles_AppendStyleSheet(
1669 styles: &mut RawServoAuthorStyles,
1670 sheet: *const DomStyleSheet,
1671 ) {
1672 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1673
1674 let global_style_data = &*GLOBAL_STYLE_DATA;
1675 let guard = global_style_data.shared_lock.read();
1676 let sheet = GeckoStyleSheet::new(sheet);
1677 styles.stylesheets.append_stylesheet(None, sheet, &guard);
1678 }
1679
1680 #[no_mangle]
Servo_AuthorStyles_InsertStyleSheetBefore( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, before_sheet: *const DomStyleSheet, )1681 pub unsafe extern "C" fn Servo_AuthorStyles_InsertStyleSheetBefore(
1682 styles: &mut RawServoAuthorStyles,
1683 sheet: *const DomStyleSheet,
1684 before_sheet: *const DomStyleSheet,
1685 ) {
1686 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1687
1688 let global_style_data = &*GLOBAL_STYLE_DATA;
1689 let guard = global_style_data.shared_lock.read();
1690 styles.stylesheets.insert_stylesheet_before(
1691 None,
1692 GeckoStyleSheet::new(sheet),
1693 GeckoStyleSheet::new(before_sheet),
1694 &guard,
1695 );
1696 }
1697
1698 #[no_mangle]
Servo_AuthorStyles_RemoveStyleSheet( styles: &mut RawServoAuthorStyles, sheet: *const DomStyleSheet, )1699 pub unsafe extern "C" fn Servo_AuthorStyles_RemoveStyleSheet(
1700 styles: &mut RawServoAuthorStyles,
1701 sheet: *const DomStyleSheet,
1702 ) {
1703 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1704
1705 let global_style_data = &*GLOBAL_STYLE_DATA;
1706 let guard = global_style_data.shared_lock.read();
1707 styles
1708 .stylesheets
1709 .remove_stylesheet(None, GeckoStyleSheet::new(sheet), &guard);
1710 }
1711
1712 #[no_mangle]
Servo_AuthorStyles_ForceDirty(styles: &mut RawServoAuthorStyles)1713 pub unsafe extern "C" fn Servo_AuthorStyles_ForceDirty(styles: &mut RawServoAuthorStyles) {
1714 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1715 styles.stylesheets.force_dirty();
1716 }
1717
1718 #[no_mangle]
Servo_AuthorStyles_IsDirty(styles: &RawServoAuthorStyles) -> bool1719 pub unsafe extern "C" fn Servo_AuthorStyles_IsDirty(styles: &RawServoAuthorStyles) -> bool {
1720 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
1721 styles.stylesheets.dirty()
1722 }
1723
1724 #[no_mangle]
Servo_AuthorStyles_Flush( styles: &mut RawServoAuthorStyles, document_set: &RawServoStyleSet, )1725 pub unsafe extern "C" fn Servo_AuthorStyles_Flush(
1726 styles: &mut RawServoAuthorStyles,
1727 document_set: &RawServoStyleSet,
1728 ) {
1729 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(styles);
1730 // Try to avoid the atomic borrow below if possible.
1731 if !styles.stylesheets.dirty() {
1732 return;
1733 }
1734
1735 let global_style_data = &*GLOBAL_STYLE_DATA;
1736 let guard = global_style_data.shared_lock.read();
1737
1738 let document_data = PerDocumentStyleData::from_ffi(document_set).borrow();
1739
1740 let stylist = &document_data.stylist;
1741
1742 // TODO(emilio): This is going to need an element or something to do proper
1743 // invalidation in Shadow roots.
1744 styles.flush::<GeckoElement>(stylist.device(), stylist.quirks_mode(), &guard);
1745 }
1746
1747 #[no_mangle]
Servo_DeclarationBlock_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, declarations: &RawServoDeclarationBlock, ) -> usize1748 pub unsafe extern "C" fn Servo_DeclarationBlock_SizeOfIncludingThis(
1749 malloc_size_of: GeckoMallocSizeOf,
1750 malloc_enclosing_size_of: GeckoMallocSizeOf,
1751 declarations: &RawServoDeclarationBlock,
1752 ) -> usize {
1753 use malloc_size_of::MallocSizeOf;
1754 use malloc_size_of::MallocUnconditionalShallowSizeOf;
1755
1756 let global_style_data = &*GLOBAL_STYLE_DATA;
1757 let guard = global_style_data.shared_lock.read();
1758
1759 let mut ops = MallocSizeOfOps::new(
1760 malloc_size_of.unwrap(),
1761 Some(malloc_enclosing_size_of.unwrap()),
1762 None,
1763 );
1764
1765 Locked::<PropertyDeclarationBlock>::as_arc(&declarations).with_arc(|declarations| {
1766 let mut n = 0;
1767 n += declarations.unconditional_shallow_size_of(&mut ops);
1768 n += declarations.read_with(&guard).size_of(&mut ops);
1769 n
1770 })
1771 }
1772
1773 #[no_mangle]
Servo_AuthorStyles_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, styles: &RawServoAuthorStyles, ) -> usize1774 pub unsafe extern "C" fn Servo_AuthorStyles_SizeOfIncludingThis(
1775 malloc_size_of: GeckoMallocSizeOf,
1776 malloc_enclosing_size_of: GeckoMallocSizeOf,
1777 styles: &RawServoAuthorStyles,
1778 ) -> usize {
1779 // We cannot `use` MallocSizeOf at the top level, otherwise the compiler
1780 // would complain in `Servo_StyleSheet_SizeOfIncludingThis` for `size_of`
1781 // there.
1782 use malloc_size_of::MallocSizeOf;
1783 let malloc_size_of = malloc_size_of.unwrap();
1784 let malloc_size_of_this =
1785 malloc_size_of(styles as *const RawServoAuthorStyles as *const c_void);
1786
1787 let styles = AuthorStyles::<GeckoStyleSheet>::from_ffi(styles);
1788 let mut ops = MallocSizeOfOps::new(
1789 malloc_size_of,
1790 Some(malloc_enclosing_size_of.unwrap()),
1791 None,
1792 );
1793 malloc_size_of_this + styles.size_of(&mut ops)
1794 }
1795
1796 #[no_mangle]
Servo_StyleSet_MediumFeaturesChanged( document_set: &RawServoStyleSet, non_document_styles: &mut nsTArray<&mut RawServoAuthorStyles>, may_affect_default_style: bool, ) -> structs::MediumFeaturesChangedResult1797 pub unsafe extern "C" fn Servo_StyleSet_MediumFeaturesChanged(
1798 document_set: &RawServoStyleSet,
1799 non_document_styles: &mut nsTArray<&mut RawServoAuthorStyles>,
1800 may_affect_default_style: bool,
1801 ) -> structs::MediumFeaturesChangedResult {
1802 let global_style_data = &*GLOBAL_STYLE_DATA;
1803 let guard = global_style_data.shared_lock.read();
1804
1805 // NOTE(emilio): We don't actually need to flush the stylist here and ensure
1806 // it's up to date.
1807 //
1808 // In case it isn't we would trigger a rebuild + restyle as needed too.
1809 //
1810 // We need to ensure the default computed values are up to date though,
1811 // because those can influence the result of media query evaluation.
1812 let mut document_data = PerDocumentStyleData::from_ffi(document_set).borrow_mut();
1813
1814 if may_affect_default_style {
1815 document_data.stylist.device_mut().reset_computed_values();
1816 }
1817 let guards = StylesheetGuards::same(&guard);
1818
1819 let origins_in_which_rules_changed = document_data
1820 .stylist
1821 .media_features_change_changed_style(&guards, document_data.stylist.device());
1822
1823 let affects_document_rules = !origins_in_which_rules_changed.is_empty();
1824 if affects_document_rules {
1825 document_data
1826 .stylist
1827 .force_stylesheet_origins_dirty(origins_in_which_rules_changed);
1828 }
1829
1830 let mut affects_non_document_rules = false;
1831 for author_styles in &mut **non_document_styles {
1832 let author_styles = AuthorStyles::<GeckoStyleSheet>::from_ffi_mut(&mut *author_styles);
1833 let affected_style = author_styles.stylesheets.iter().any(|sheet| {
1834 !author_styles.data.media_feature_affected_matches(
1835 sheet,
1836 &guards.author,
1837 document_data.stylist.device(),
1838 document_data.stylist.quirks_mode(),
1839 )
1840 });
1841 if affected_style {
1842 affects_non_document_rules = true;
1843 author_styles.stylesheets.force_dirty();
1844 }
1845 }
1846
1847 let uses_viewport_units = document_data.stylist.device().used_viewport_size();
1848
1849 structs::MediumFeaturesChangedResult {
1850 mAffectsDocumentRules: affects_document_rules,
1851 mAffectsNonDocumentRules: affects_non_document_rules,
1852 mUsesViewportUnits: uses_viewport_units,
1853 }
1854 }
1855
1856 #[no_mangle]
Servo_StyleSet_InsertStyleSheetBefore( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, before_sheet: *const DomStyleSheet, )1857 pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(
1858 raw_data: &RawServoStyleSet,
1859 sheet: *const DomStyleSheet,
1860 before_sheet: *const DomStyleSheet,
1861 ) {
1862 let global_style_data = &*GLOBAL_STYLE_DATA;
1863 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1864 let data = &mut *data;
1865 let guard = global_style_data.shared_lock.read();
1866 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1867 data.stylist.insert_stylesheet_before(
1868 sheet,
1869 unsafe { GeckoStyleSheet::new(before_sheet) },
1870 &guard,
1871 );
1872 }
1873
1874 #[no_mangle]
Servo_StyleSet_RemoveStyleSheet( raw_data: &RawServoStyleSet, sheet: *const DomStyleSheet, )1875 pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(
1876 raw_data: &RawServoStyleSet,
1877 sheet: *const DomStyleSheet,
1878 ) {
1879 let global_style_data = &*GLOBAL_STYLE_DATA;
1880 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1881 let data = &mut *data;
1882 let guard = global_style_data.shared_lock.read();
1883 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
1884 data.stylist.remove_stylesheet(sheet, &guard);
1885 }
1886
1887 #[no_mangle]
Servo_StyleSet_GetSheetAt( raw_data: &RawServoStyleSet, origin: Origin, index: usize, ) -> *const DomStyleSheet1888 pub unsafe extern "C" fn Servo_StyleSet_GetSheetAt(
1889 raw_data: &RawServoStyleSet,
1890 origin: Origin,
1891 index: usize,
1892 ) -> *const DomStyleSheet {
1893 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
1894 data.stylist
1895 .sheet_at(origin, index)
1896 .map_or(ptr::null(), |s| s.raw())
1897 }
1898
1899 #[no_mangle]
Servo_StyleSet_GetSheetCount( raw_data: &RawServoStyleSet, origin: Origin, ) -> usize1900 pub unsafe extern "C" fn Servo_StyleSet_GetSheetCount(
1901 raw_data: &RawServoStyleSet,
1902 origin: Origin,
1903 ) -> usize {
1904 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
1905 data.stylist.sheet_count(origin)
1906 }
1907
1908 #[no_mangle]
Servo_StyleSet_FlushStyleSheets( raw_data: &RawServoStyleSet, doc_element: Option<&RawGeckoElement>, snapshots: *const ServoElementSnapshotTable, )1909 pub unsafe extern "C" fn Servo_StyleSet_FlushStyleSheets(
1910 raw_data: &RawServoStyleSet,
1911 doc_element: Option<&RawGeckoElement>,
1912 snapshots: *const ServoElementSnapshotTable,
1913 ) {
1914 let global_style_data = &*GLOBAL_STYLE_DATA;
1915 let guard = global_style_data.shared_lock.read();
1916 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1917 let doc_element = doc_element.map(GeckoElement);
1918
1919 let have_invalidations = data.flush_stylesheets(&guard, doc_element, snapshots.as_ref());
1920
1921 if have_invalidations && doc_element.is_some() {
1922 // The invalidation machinery propagates the bits up, but we still need
1923 // to tell the Gecko restyle root machinery about it.
1924 bindings::Gecko_NoteDirtySubtreeForInvalidation(doc_element.unwrap().0);
1925 }
1926 }
1927
1928 #[no_mangle]
Servo_StyleSet_NoteStyleSheetsChanged( raw_data: &RawServoStyleSet, changed_origins: OriginFlags, )1929 pub extern "C" fn Servo_StyleSet_NoteStyleSheetsChanged(
1930 raw_data: &RawServoStyleSet,
1931 changed_origins: OriginFlags,
1932 ) {
1933 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1934 data.stylist
1935 .force_stylesheet_origins_dirty(OriginSet::from(changed_origins));
1936 }
1937
1938 #[no_mangle]
Servo_StyleSet_SetAuthorStyleDisabled( raw_data: &RawServoStyleSet, author_style_disabled: bool, )1939 pub extern "C" fn Servo_StyleSet_SetAuthorStyleDisabled(
1940 raw_data: &RawServoStyleSet,
1941 author_style_disabled: bool,
1942 ) {
1943 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
1944 let enabled = if author_style_disabled {
1945 AuthorStylesEnabled::No
1946 } else {
1947 AuthorStylesEnabled::Yes
1948 };
1949 data.stylist.set_author_styles_enabled(enabled);
1950 }
1951
1952 #[no_mangle]
Servo_StyleSheet_HasRules(raw_contents: &RawServoStyleSheetContents) -> bool1953 pub extern "C" fn Servo_StyleSheet_HasRules(raw_contents: &RawServoStyleSheetContents) -> bool {
1954 let global_style_data = &*GLOBAL_STYLE_DATA;
1955 let guard = global_style_data.shared_lock.read();
1956 !StylesheetContents::as_arc(&raw_contents)
1957 .rules
1958 .read_with(&guard)
1959 .0
1960 .is_empty()
1961 }
1962
1963 #[no_mangle]
Servo_StyleSheet_GetRules( sheet: &RawServoStyleSheetContents, ) -> Strong<ServoCssRules>1964 pub extern "C" fn Servo_StyleSheet_GetRules(
1965 sheet: &RawServoStyleSheetContents,
1966 ) -> Strong<ServoCssRules> {
1967 StylesheetContents::as_arc(&sheet)
1968 .rules
1969 .clone()
1970 .into_strong()
1971 }
1972
1973 #[no_mangle]
Servo_StyleSheet_Clone( raw_sheet: &RawServoStyleSheetContents, reference_sheet: *const DomStyleSheet, ) -> Strong<RawServoStyleSheetContents>1974 pub extern "C" fn Servo_StyleSheet_Clone(
1975 raw_sheet: &RawServoStyleSheetContents,
1976 reference_sheet: *const DomStyleSheet,
1977 ) -> Strong<RawServoStyleSheetContents> {
1978 use style::shared_lock::{DeepCloneParams, DeepCloneWithLock};
1979 let global_style_data = &*GLOBAL_STYLE_DATA;
1980 let guard = global_style_data.shared_lock.read();
1981 let contents = StylesheetContents::as_arc(&raw_sheet);
1982 let params = DeepCloneParams { reference_sheet };
1983
1984 Arc::new(contents.deep_clone_with_lock(&global_style_data.shared_lock, &guard, ¶ms))
1985 .into_strong()
1986 }
1987
1988 #[no_mangle]
Servo_StyleSheet_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sheet: &RawServoStyleSheetContents, ) -> usize1989 pub extern "C" fn Servo_StyleSheet_SizeOfIncludingThis(
1990 malloc_size_of: GeckoMallocSizeOf,
1991 malloc_enclosing_size_of: GeckoMallocSizeOf,
1992 sheet: &RawServoStyleSheetContents,
1993 ) -> usize {
1994 let global_style_data = &*GLOBAL_STYLE_DATA;
1995 let guard = global_style_data.shared_lock.read();
1996 let mut ops = MallocSizeOfOps::new(
1997 malloc_size_of.unwrap(),
1998 Some(malloc_enclosing_size_of.unwrap()),
1999 None,
2000 );
2001 // TODO(emilio): We're not measuring the size of the Arc<StyleSheetContents>
2002 // allocation itself here.
2003 StylesheetContents::as_arc(&sheet).size_of(&guard, &mut ops)
2004 }
2005
2006 #[no_mangle]
Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin2007 pub extern "C" fn Servo_StyleSheet_GetOrigin(sheet: &RawServoStyleSheetContents) -> Origin {
2008 StylesheetContents::as_arc(&sheet).origin
2009 }
2010
2011 #[no_mangle]
Servo_StyleSheet_GetSourceMapURL( sheet: &RawServoStyleSheetContents, result: &mut nsAString, )2012 pub extern "C" fn Servo_StyleSheet_GetSourceMapURL(
2013 sheet: &RawServoStyleSheetContents,
2014 result: &mut nsAString,
2015 ) {
2016 let contents = StylesheetContents::as_arc(&sheet);
2017 let url_opt = contents.source_map_url.read();
2018 if let Some(ref url) = *url_opt {
2019 write!(result, "{}", url).unwrap();
2020 }
2021 }
2022
2023 #[no_mangle]
Servo_StyleSheet_GetSourceURL( sheet: &RawServoStyleSheetContents, result: &mut nsAString, )2024 pub extern "C" fn Servo_StyleSheet_GetSourceURL(
2025 sheet: &RawServoStyleSheetContents,
2026 result: &mut nsAString,
2027 ) {
2028 let contents = StylesheetContents::as_arc(&sheet);
2029 let url_opt = contents.source_url.read();
2030 if let Some(ref url) = *url_opt {
2031 write!(result, "{}", url).unwrap();
2032 }
2033 }
2034
read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2035 fn read_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2036 where
2037 Locked<T>: HasArcFFI,
2038 F: FnOnce(&T) -> R,
2039 {
2040 let global_style_data = &*GLOBAL_STYLE_DATA;
2041 let guard = global_style_data.shared_lock.read();
2042 func(Locked::<T>::as_arc(&raw).read_with(&guard))
2043 }
2044
2045 #[cfg(debug_assertions)]
read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2046 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2047 where
2048 Locked<T>: HasArcFFI,
2049 F: FnOnce(&T) -> R,
2050 {
2051 debug_assert!(is_main_thread() && !is_in_servo_traversal());
2052 read_locked_arc(raw, func)
2053 }
2054
2055 #[cfg(not(debug_assertions))]
read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&T) -> R,2056 unsafe fn read_locked_arc_unchecked<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2057 where
2058 Locked<T>: HasArcFFI,
2059 F: FnOnce(&T) -> R,
2060 {
2061 func(Locked::<T>::as_arc(&raw).read_unchecked())
2062 }
2063
write_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R where Locked<T>: HasArcFFI, F: FnOnce(&mut T) -> R,2064 fn write_locked_arc<T, R, F>(raw: &<Locked<T> as HasFFI>::FFIType, func: F) -> R
2065 where
2066 Locked<T>: HasArcFFI,
2067 F: FnOnce(&mut T) -> R,
2068 {
2069 let global_style_data = &*GLOBAL_STYLE_DATA;
2070 let mut guard = global_style_data.shared_lock.write();
2071 func(Locked::<T>::as_arc(&raw).write_with(&mut guard))
2072 }
2073
2074 #[no_mangle]
Servo_CssRules_ListTypes(rules: &ServoCssRules, result: &mut nsTArray<usize>)2075 pub extern "C" fn Servo_CssRules_ListTypes(rules: &ServoCssRules, result: &mut nsTArray<usize>) {
2076 read_locked_arc(rules, |rules: &CssRules| {
2077 result.assign_from_iter_pod(rules.0.iter().map(|rule| rule.rule_type() as usize));
2078 })
2079 }
2080
2081 #[no_mangle]
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, ) -> nsresult2082 pub extern "C" fn Servo_CssRules_InsertRule(
2083 rules: &ServoCssRules,
2084 contents: &RawServoStyleSheetContents,
2085 rule: &nsACString,
2086 index: u32,
2087 nested: bool,
2088 loader: *mut Loader,
2089 allow_import_rules: AllowImportRules,
2090 gecko_stylesheet: *mut DomStyleSheet,
2091 rule_type: *mut u16,
2092 ) -> nsresult {
2093 let loader = if loader.is_null() {
2094 None
2095 } else {
2096 Some(StylesheetLoader::new(
2097 loader,
2098 gecko_stylesheet,
2099 ptr::null_mut(),
2100 ptr::null_mut(),
2101 ))
2102 };
2103 let loader = loader
2104 .as_ref()
2105 .map(|loader| loader as &dyn StyleStylesheetLoader);
2106 let rule = unsafe { rule.as_str_unchecked() };
2107
2108 let global_style_data = &*GLOBAL_STYLE_DATA;
2109 let contents = StylesheetContents::as_arc(&contents);
2110 let result = Locked::<CssRules>::as_arc(&rules).insert_rule(
2111 &global_style_data.shared_lock,
2112 rule,
2113 contents,
2114 index as usize,
2115 nested,
2116 loader,
2117 allow_import_rules,
2118 );
2119
2120 match result {
2121 Ok(new_rule) => {
2122 *unsafe { rule_type.as_mut().unwrap() } = new_rule.rule_type() as u16;
2123 nsresult::NS_OK
2124 },
2125 Err(err) => err.into(),
2126 }
2127 }
2128
2129 #[no_mangle]
Servo_CssRules_DeleteRule(rules: &ServoCssRules, index: u32) -> nsresult2130 pub extern "C" fn Servo_CssRules_DeleteRule(rules: &ServoCssRules, index: u32) -> nsresult {
2131 write_locked_arc(rules, |rules: &mut CssRules| {
2132 match rules.remove_rule(index as usize) {
2133 Ok(_) => nsresult::NS_OK,
2134 Err(err) => err.into(),
2135 }
2136 })
2137 }
2138
2139 macro_rules! impl_basic_rule_funcs_without_getter {
2140 { ($rule_type:ty, $raw_type:ty),
2141 debug: $debug:ident,
2142 to_css: $to_css:ident,
2143 } => {
2144 #[cfg(debug_assertions)]
2145 #[no_mangle]
2146 pub extern "C" fn $debug(rule: &$raw_type, result: *mut nsACString) {
2147 read_locked_arc(rule, |rule: &$rule_type| {
2148 write!(unsafe { result.as_mut().unwrap() }, "{:?}", *rule).unwrap();
2149 })
2150 }
2151
2152 #[cfg(not(debug_assertions))]
2153 #[no_mangle]
2154 pub extern "C" fn $debug(_: &$raw_type, _: *mut nsACString) {
2155 unreachable!()
2156 }
2157
2158 #[no_mangle]
2159 pub extern "C" fn $to_css(rule: &$raw_type, result: &mut nsAString) {
2160 let global_style_data = &*GLOBAL_STYLE_DATA;
2161 let guard = global_style_data.shared_lock.read();
2162 let rule = Locked::<$rule_type>::as_arc(&rule);
2163 rule.read_with(&guard).to_css(&guard, result).unwrap();
2164 }
2165 }
2166 }
2167
2168 macro_rules! impl_basic_rule_funcs {
2169 { ($name:ident, $rule_type:ty, $raw_type:ty),
2170 getter: $getter:ident,
2171 debug: $debug:ident,
2172 to_css: $to_css:ident,
2173 } => {
2174 #[no_mangle]
2175 pub extern "C" fn $getter(
2176 rules: &ServoCssRules,
2177 index: u32,
2178 line: *mut u32,
2179 column: *mut u32,
2180 ) -> Strong<$raw_type> {
2181 let global_style_data = &*GLOBAL_STYLE_DATA;
2182 let guard = global_style_data.shared_lock.read();
2183 let rules = Locked::<CssRules>::as_arc(&rules).read_with(&guard);
2184 let index = index as usize;
2185
2186 if index >= rules.0.len() {
2187 return Strong::null();
2188 }
2189
2190 match rules.0[index] {
2191 CssRule::$name(ref rule) => {
2192 let location = rule.read_with(&guard).source_location;
2193 *unsafe { line.as_mut().unwrap() } = location.line as u32;
2194 *unsafe { column.as_mut().unwrap() } = location.column as u32;
2195 rule.clone().into_strong()
2196 },
2197 _ => {
2198 Strong::null()
2199 }
2200 }
2201 }
2202
2203 impl_basic_rule_funcs_without_getter! { ($rule_type, $raw_type),
2204 debug: $debug,
2205 to_css: $to_css,
2206 }
2207 }
2208 }
2209
2210 macro_rules! impl_group_rule_funcs {
2211 { ($name:ident, $rule_type:ty, $raw_type:ty),
2212 get_rules: $get_rules:ident,
2213 $($basic:tt)+
2214 } => {
2215 impl_basic_rule_funcs! { ($name, $rule_type, $raw_type), $($basic)+ }
2216
2217 #[no_mangle]
2218 pub extern "C" fn $get_rules(rule: &$raw_type) -> Strong<ServoCssRules> {
2219 read_locked_arc(rule, |rule: &$rule_type| {
2220 rule.rules.clone().into_strong()
2221 })
2222 }
2223 }
2224 }
2225
2226 impl_basic_rule_funcs! { (Style, StyleRule, RawServoStyleRule),
2227 getter: Servo_CssRules_GetStyleRuleAt,
2228 debug: Servo_StyleRule_Debug,
2229 to_css: Servo_StyleRule_GetCssText,
2230 }
2231
2232 impl_basic_rule_funcs! { (Import, ImportRule, RawServoImportRule),
2233 getter: Servo_CssRules_GetImportRuleAt,
2234 debug: Servo_ImportRule_Debug,
2235 to_css: Servo_ImportRule_GetCssText,
2236 }
2237
2238 impl_basic_rule_funcs_without_getter! { (Keyframe, RawServoKeyframe),
2239 debug: Servo_Keyframe_Debug,
2240 to_css: Servo_Keyframe_GetCssText,
2241 }
2242
2243 impl_basic_rule_funcs! { (Keyframes, KeyframesRule, RawServoKeyframesRule),
2244 getter: Servo_CssRules_GetKeyframesRuleAt,
2245 debug: Servo_KeyframesRule_Debug,
2246 to_css: Servo_KeyframesRule_GetCssText,
2247 }
2248
2249 impl_group_rule_funcs! { (Media, MediaRule, RawServoMediaRule),
2250 get_rules: Servo_MediaRule_GetRules,
2251 getter: Servo_CssRules_GetMediaRuleAt,
2252 debug: Servo_MediaRule_Debug,
2253 to_css: Servo_MediaRule_GetCssText,
2254 }
2255
2256 impl_basic_rule_funcs! { (Namespace, NamespaceRule, RawServoNamespaceRule),
2257 getter: Servo_CssRules_GetNamespaceRuleAt,
2258 debug: Servo_NamespaceRule_Debug,
2259 to_css: Servo_NamespaceRule_GetCssText,
2260 }
2261
2262 impl_basic_rule_funcs! { (Page, PageRule, RawServoPageRule),
2263 getter: Servo_CssRules_GetPageRuleAt,
2264 debug: Servo_PageRule_Debug,
2265 to_css: Servo_PageRule_GetCssText,
2266 }
2267
2268 impl_group_rule_funcs! { (Supports, SupportsRule, RawServoSupportsRule),
2269 get_rules: Servo_SupportsRule_GetRules,
2270 getter: Servo_CssRules_GetSupportsRuleAt,
2271 debug: Servo_SupportsRule_Debug,
2272 to_css: Servo_SupportsRule_GetCssText,
2273 }
2274
2275 impl_group_rule_funcs! { (Document, DocumentRule, RawServoMozDocumentRule),
2276 get_rules: Servo_MozDocumentRule_GetRules,
2277 getter: Servo_CssRules_GetMozDocumentRuleAt,
2278 debug: Servo_MozDocumentRule_Debug,
2279 to_css: Servo_MozDocumentRule_GetCssText,
2280 }
2281
2282 impl_basic_rule_funcs! { (FontFeatureValues, FontFeatureValuesRule, RawServoFontFeatureValuesRule),
2283 getter: Servo_CssRules_GetFontFeatureValuesRuleAt,
2284 debug: Servo_FontFeatureValuesRule_Debug,
2285 to_css: Servo_FontFeatureValuesRule_GetCssText,
2286 }
2287
2288 impl_basic_rule_funcs! { (FontFace, FontFaceRule, RawServoFontFaceRule),
2289 getter: Servo_CssRules_GetFontFaceRuleAt,
2290 debug: Servo_FontFaceRule_Debug,
2291 to_css: Servo_FontFaceRule_GetCssText,
2292 }
2293
2294 impl_basic_rule_funcs! { (CounterStyle, CounterStyleRule, RawServoCounterStyleRule),
2295 getter: Servo_CssRules_GetCounterStyleRuleAt,
2296 debug: Servo_CounterStyleRule_Debug,
2297 to_css: Servo_CounterStyleRule_GetCssText,
2298 }
2299
2300 #[no_mangle]
Servo_StyleRule_GetStyle( rule: &RawServoStyleRule, ) -> Strong<RawServoDeclarationBlock>2301 pub extern "C" fn Servo_StyleRule_GetStyle(
2302 rule: &RawServoStyleRule,
2303 ) -> Strong<RawServoDeclarationBlock> {
2304 read_locked_arc(rule, |rule: &StyleRule| rule.block.clone().into_strong())
2305 }
2306
2307 #[no_mangle]
Servo_StyleRule_SetStyle( rule: &RawServoStyleRule, declarations: &RawServoDeclarationBlock, )2308 pub extern "C" fn Servo_StyleRule_SetStyle(
2309 rule: &RawServoStyleRule,
2310 declarations: &RawServoDeclarationBlock,
2311 ) {
2312 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2313 write_locked_arc(rule, |rule: &mut StyleRule| {
2314 rule.block = declarations.clone_arc();
2315 })
2316 }
2317
2318 #[no_mangle]
Servo_StyleRule_GetSelectorText( rule: &RawServoStyleRule, result: &mut nsAString, )2319 pub extern "C" fn Servo_StyleRule_GetSelectorText(
2320 rule: &RawServoStyleRule,
2321 result: &mut nsAString,
2322 ) {
2323 read_locked_arc(rule, |rule: &StyleRule| {
2324 rule.selectors.to_css(result).unwrap();
2325 })
2326 }
2327
2328 #[no_mangle]
Servo_StyleRule_GetSelectorTextAtIndex( rule: &RawServoStyleRule, index: u32, result: &mut nsAString, )2329 pub extern "C" fn Servo_StyleRule_GetSelectorTextAtIndex(
2330 rule: &RawServoStyleRule,
2331 index: u32,
2332 result: &mut nsAString,
2333 ) {
2334 read_locked_arc(rule, |rule: &StyleRule| {
2335 let index = index as usize;
2336 if index >= rule.selectors.0.len() {
2337 return;
2338 }
2339 rule.selectors.0[index].to_css(result).unwrap();
2340 })
2341 }
2342
2343 #[no_mangle]
Servo_StyleRule_GetSelectorCount(rule: &RawServoStyleRule, count: *mut u32)2344 pub extern "C" fn Servo_StyleRule_GetSelectorCount(rule: &RawServoStyleRule, count: *mut u32) {
2345 read_locked_arc(rule, |rule: &StyleRule| {
2346 *unsafe { count.as_mut().unwrap() } = rule.selectors.0.len() as u32;
2347 })
2348 }
2349
2350 #[no_mangle]
Servo_StyleRule_GetSpecificityAtIndex( rule: &RawServoStyleRule, index: u32, specificity: *mut u64, )2351 pub extern "C" fn Servo_StyleRule_GetSpecificityAtIndex(
2352 rule: &RawServoStyleRule,
2353 index: u32,
2354 specificity: *mut u64,
2355 ) {
2356 read_locked_arc(rule, |rule: &StyleRule| {
2357 let specificity = unsafe { specificity.as_mut().unwrap() };
2358 let index = index as usize;
2359 if index >= rule.selectors.0.len() {
2360 *specificity = 0;
2361 return;
2362 }
2363 *specificity = rule.selectors.0[index].specificity() as u64;
2364 })
2365 }
2366
2367 #[no_mangle]
Servo_StyleRule_SelectorMatchesElement( rule: &RawServoStyleRule, element: &RawGeckoElement, index: u32, pseudo_type: PseudoStyleType, relevant_link_visited: bool, ) -> bool2368 pub extern "C" fn Servo_StyleRule_SelectorMatchesElement(
2369 rule: &RawServoStyleRule,
2370 element: &RawGeckoElement,
2371 index: u32,
2372 pseudo_type: PseudoStyleType,
2373 relevant_link_visited: bool,
2374 ) -> bool {
2375 read_locked_arc(rule, |rule: &StyleRule| {
2376 let index = index as usize;
2377 if index >= rule.selectors.0.len() {
2378 return false;
2379 }
2380
2381 let selector = &rule.selectors.0[index];
2382 let mut matching_mode = MatchingMode::Normal;
2383
2384 match PseudoElement::from_pseudo_type(pseudo_type) {
2385 Some(pseudo) => {
2386 // We need to make sure that the requested pseudo element type
2387 // matches the selector pseudo element type before proceeding.
2388 match selector.pseudo_element() {
2389 Some(selector_pseudo) if *selector_pseudo == pseudo => {
2390 matching_mode = MatchingMode::ForStatelessPseudoElement
2391 },
2392 _ => return false,
2393 };
2394 },
2395 None => {
2396 // Do not attempt to match if a pseudo element is requested and
2397 // this is not a pseudo element selector, or vice versa.
2398 if selector.has_pseudo_element() {
2399 return false;
2400 }
2401 },
2402 };
2403
2404 let element = GeckoElement(element);
2405 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2406 let visited_mode =
2407 if relevant_link_visited {
2408 VisitedHandlingMode::RelevantLinkVisited
2409 } else {
2410 VisitedHandlingMode::AllLinksUnvisited
2411 };
2412 let mut ctx =
2413 MatchingContext::new_for_visited(matching_mode, None, None, visited_mode, quirks_mode);
2414 matches_selector(selector, 0, None, &element, &mut ctx, &mut |_, _| {})
2415 })
2416 }
2417
2418 #[no_mangle]
Servo_StyleRule_SetSelectorText( sheet: &RawServoStyleSheetContents, rule: &RawServoStyleRule, text: &nsAString, ) -> bool2419 pub extern "C" fn Servo_StyleRule_SetSelectorText(
2420 sheet: &RawServoStyleSheetContents,
2421 rule: &RawServoStyleRule,
2422 text: &nsAString,
2423 ) -> bool {
2424 let value_str = text.to_string();
2425
2426 write_locked_arc(rule, |rule: &mut StyleRule| {
2427 use style::selector_parser::SelectorParser;
2428
2429 let contents = StylesheetContents::as_arc(&sheet);
2430 let namespaces = contents.namespaces.read();
2431 let url_data = contents.url_data.read();
2432 let parser = SelectorParser {
2433 stylesheet_origin: contents.origin,
2434 namespaces: &namespaces,
2435 url_data: Some(&url_data),
2436 };
2437
2438 let mut parser_input = ParserInput::new(&value_str);
2439 match SelectorList::parse(&parser, &mut Parser::new(&mut parser_input)) {
2440 Ok(selectors) => {
2441 rule.selectors = selectors;
2442 true
2443 },
2444 Err(_) => false,
2445 }
2446 })
2447 }
2448
2449 #[no_mangle]
Servo_SelectorList_Closest( element: &RawGeckoElement, selectors: &RawServoSelectorList, ) -> *const RawGeckoElement2450 pub unsafe extern "C" fn Servo_SelectorList_Closest(
2451 element: &RawGeckoElement,
2452 selectors: &RawServoSelectorList,
2453 ) -> *const RawGeckoElement {
2454 use std::borrow::Borrow;
2455 use style::dom_apis;
2456
2457 let element = GeckoElement(element);
2458 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2459 let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2460
2461 dom_apis::element_closest(element, &selectors, quirks_mode).map_or(ptr::null(), |e| e.0)
2462 }
2463
2464 #[no_mangle]
Servo_SelectorList_Matches( element: &RawGeckoElement, selectors: &RawServoSelectorList, ) -> bool2465 pub unsafe extern "C" fn Servo_SelectorList_Matches(
2466 element: &RawGeckoElement,
2467 selectors: &RawServoSelectorList,
2468 ) -> bool {
2469 use std::borrow::Borrow;
2470 use style::dom_apis;
2471
2472 let element = GeckoElement(element);
2473 let quirks_mode = element.as_node().owner_doc().quirks_mode();
2474 let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2475 dom_apis::element_matches(&element, &selectors, quirks_mode)
2476 }
2477
2478 #[no_mangle]
Servo_SelectorList_QueryFirst( node: &RawGeckoNode, selectors: &RawServoSelectorList, may_use_invalidation: bool, ) -> *const RawGeckoElement2479 pub unsafe extern "C" fn Servo_SelectorList_QueryFirst(
2480 node: &RawGeckoNode,
2481 selectors: &RawServoSelectorList,
2482 may_use_invalidation: bool,
2483 ) -> *const RawGeckoElement {
2484 use std::borrow::Borrow;
2485 use style::dom_apis::{self, MayUseInvalidation, QueryFirst};
2486
2487 let node = GeckoNode(node);
2488 let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2489 let mut result = None;
2490
2491 let may_use_invalidation = if may_use_invalidation {
2492 MayUseInvalidation::Yes
2493 } else {
2494 MayUseInvalidation::No
2495 };
2496
2497 dom_apis::query_selector::<GeckoElement, QueryFirst>(
2498 node,
2499 &selectors,
2500 &mut result,
2501 may_use_invalidation,
2502 );
2503
2504 result.map_or(ptr::null(), |e| e.0)
2505 }
2506
2507 #[no_mangle]
Servo_SelectorList_QueryAll( node: &RawGeckoNode, selectors: &RawServoSelectorList, content_list: *mut structs::nsSimpleContentList, may_use_invalidation: bool, )2508 pub unsafe extern "C" fn Servo_SelectorList_QueryAll(
2509 node: &RawGeckoNode,
2510 selectors: &RawServoSelectorList,
2511 content_list: *mut structs::nsSimpleContentList,
2512 may_use_invalidation: bool,
2513 ) {
2514 use std::borrow::Borrow;
2515 use style::dom_apis::{self, MayUseInvalidation, QueryAll};
2516
2517 let node = GeckoNode(node);
2518 let selectors = ::selectors::SelectorList::from_ffi(selectors).borrow();
2519 let mut result = SmallVec::new();
2520
2521 let may_use_invalidation = if may_use_invalidation {
2522 MayUseInvalidation::Yes
2523 } else {
2524 MayUseInvalidation::No
2525 };
2526
2527 dom_apis::query_selector::<GeckoElement, QueryAll>(
2528 node,
2529 &selectors,
2530 &mut result,
2531 may_use_invalidation,
2532 );
2533
2534 if !result.is_empty() {
2535 // NOTE(emilio): This relies on a slice of GeckoElement having the same
2536 // memory representation than a slice of element pointers.
2537 bindings::Gecko_ContentList_AppendAll(
2538 content_list,
2539 result.as_ptr() as *mut *const _,
2540 result.len(),
2541 )
2542 }
2543 }
2544
2545 #[no_mangle]
Servo_ImportRule_GetHref(rule: &RawServoImportRule, result: &mut nsAString)2546 pub extern "C" fn Servo_ImportRule_GetHref(rule: &RawServoImportRule, result: &mut nsAString) {
2547 read_locked_arc(rule, |rule: &ImportRule| {
2548 write!(result, "{}", rule.url.as_str()).unwrap();
2549 })
2550 }
2551
2552 #[no_mangle]
Servo_ImportRule_GetSheet(rule: &RawServoImportRule) -> *const DomStyleSheet2553 pub extern "C" fn Servo_ImportRule_GetSheet(rule: &RawServoImportRule) -> *const DomStyleSheet {
2554 read_locked_arc(rule, |rule: &ImportRule| {
2555 rule.stylesheet.as_sheet().unwrap().raw() as *const DomStyleSheet
2556 })
2557 }
2558
2559 #[no_mangle]
Servo_ImportRule_SetSheet(rule: &RawServoImportRule, sheet: *mut DomStyleSheet)2560 pub extern "C" fn Servo_ImportRule_SetSheet(rule: &RawServoImportRule, sheet: *mut DomStyleSheet) {
2561 write_locked_arc(rule, |rule: &mut ImportRule| {
2562 let sheet = unsafe { GeckoStyleSheet::new(sheet) };
2563 rule.stylesheet = ImportSheet::new(sheet);
2564 })
2565 }
2566
2567 #[no_mangle]
Servo_Keyframe_GetKeyText(keyframe: &RawServoKeyframe, result: &mut nsAString)2568 pub extern "C" fn Servo_Keyframe_GetKeyText(keyframe: &RawServoKeyframe, result: &mut nsAString) {
2569 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2570 keyframe.selector.to_css(&mut CssWriter::new(result)).unwrap()
2571 })
2572 }
2573
2574 #[no_mangle]
Servo_Keyframe_SetKeyText( keyframe: &RawServoKeyframe, text: &nsACString, ) -> bool2575 pub extern "C" fn Servo_Keyframe_SetKeyText(
2576 keyframe: &RawServoKeyframe,
2577 text: &nsACString,
2578 ) -> bool {
2579 let text = unsafe { text.as_str_unchecked() };
2580 let mut input = ParserInput::new(&text);
2581 if let Ok(selector) = Parser::new(&mut input).parse_entirely(KeyframeSelector::parse) {
2582 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2583 keyframe.selector = selector;
2584 });
2585 true
2586 } else {
2587 false
2588 }
2589 }
2590
2591 #[no_mangle]
Servo_Keyframe_GetStyle( keyframe: &RawServoKeyframe, ) -> Strong<RawServoDeclarationBlock>2592 pub extern "C" fn Servo_Keyframe_GetStyle(
2593 keyframe: &RawServoKeyframe,
2594 ) -> Strong<RawServoDeclarationBlock> {
2595 read_locked_arc(keyframe, |keyframe: &Keyframe| {
2596 keyframe.block.clone().into_strong()
2597 })
2598 }
2599
2600 #[no_mangle]
Servo_Keyframe_SetStyle( keyframe: &RawServoKeyframe, declarations: &RawServoDeclarationBlock, )2601 pub extern "C" fn Servo_Keyframe_SetStyle(
2602 keyframe: &RawServoKeyframe,
2603 declarations: &RawServoDeclarationBlock,
2604 ) {
2605 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2606 write_locked_arc(keyframe, |keyframe: &mut Keyframe| {
2607 keyframe.block = declarations.clone_arc();
2608 })
2609 }
2610
2611 #[no_mangle]
Servo_KeyframesRule_GetName(rule: &RawServoKeyframesRule) -> *mut nsAtom2612 pub extern "C" fn Servo_KeyframesRule_GetName(rule: &RawServoKeyframesRule) -> *mut nsAtom {
2613 read_locked_arc(rule, |rule: &KeyframesRule| rule.name.as_atom().as_ptr())
2614 }
2615
2616 #[no_mangle]
Servo_KeyframesRule_SetName( rule: &RawServoKeyframesRule, name: *mut nsAtom, )2617 pub unsafe extern "C" fn Servo_KeyframesRule_SetName(
2618 rule: &RawServoKeyframesRule,
2619 name: *mut nsAtom,
2620 ) {
2621 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2622 rule.name = KeyframesName::Ident(CustomIdent(Atom::from_addrefed(name)));
2623 })
2624 }
2625
2626 #[no_mangle]
Servo_KeyframesRule_GetCount(rule: &RawServoKeyframesRule) -> u322627 pub extern "C" fn Servo_KeyframesRule_GetCount(rule: &RawServoKeyframesRule) -> u32 {
2628 read_locked_arc(rule, |rule: &KeyframesRule| rule.keyframes.len() as u32)
2629 }
2630
2631 #[no_mangle]
Servo_KeyframesRule_GetKeyframeAt( rule: &RawServoKeyframesRule, index: u32, line: *mut u32, column: *mut u32, ) -> Strong<RawServoKeyframe>2632 pub extern "C" fn Servo_KeyframesRule_GetKeyframeAt(
2633 rule: &RawServoKeyframesRule,
2634 index: u32,
2635 line: *mut u32,
2636 column: *mut u32,
2637 ) -> Strong<RawServoKeyframe> {
2638 let global_style_data = &*GLOBAL_STYLE_DATA;
2639 let guard = global_style_data.shared_lock.read();
2640 let key = Locked::<KeyframesRule>::as_arc(&rule)
2641 .read_with(&guard)
2642 .keyframes[index as usize]
2643 .clone();
2644 let location = key.read_with(&guard).source_location;
2645 *unsafe { line.as_mut().unwrap() } = location.line as u32;
2646 *unsafe { column.as_mut().unwrap() } = location.column as u32;
2647 key.into_strong()
2648 }
2649
2650 #[no_mangle]
Servo_KeyframesRule_FindRule( rule: &RawServoKeyframesRule, key: &nsACString, ) -> u322651 pub extern "C" fn Servo_KeyframesRule_FindRule(
2652 rule: &RawServoKeyframesRule,
2653 key: &nsACString,
2654 ) -> u32 {
2655 let key = unsafe { key.as_str_unchecked() };
2656 let global_style_data = &*GLOBAL_STYLE_DATA;
2657 let guard = global_style_data.shared_lock.read();
2658 Locked::<KeyframesRule>::as_arc(&rule)
2659 .read_with(&guard)
2660 .find_rule(&guard, key)
2661 .map(|index| index as u32)
2662 .unwrap_or(u32::max_value())
2663 }
2664
2665 #[no_mangle]
Servo_KeyframesRule_AppendRule( rule: &RawServoKeyframesRule, contents: &RawServoStyleSheetContents, css: &nsACString, ) -> bool2666 pub extern "C" fn Servo_KeyframesRule_AppendRule(
2667 rule: &RawServoKeyframesRule,
2668 contents: &RawServoStyleSheetContents,
2669 css: &nsACString,
2670 ) -> bool {
2671 let css = unsafe { css.as_str_unchecked() };
2672 let contents = StylesheetContents::as_arc(&contents);
2673 let global_style_data = &*GLOBAL_STYLE_DATA;
2674
2675 match Keyframe::parse(css, &contents, &global_style_data.shared_lock) {
2676 Ok(keyframe) => {
2677 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2678 rule.keyframes.push(keyframe);
2679 });
2680 true
2681 },
2682 Err(..) => false,
2683 }
2684 }
2685
2686 #[no_mangle]
Servo_KeyframesRule_DeleteRule(rule: &RawServoKeyframesRule, index: u32)2687 pub extern "C" fn Servo_KeyframesRule_DeleteRule(rule: &RawServoKeyframesRule, index: u32) {
2688 write_locked_arc(rule, |rule: &mut KeyframesRule| {
2689 rule.keyframes.remove(index as usize);
2690 })
2691 }
2692
2693 #[no_mangle]
Servo_MediaRule_GetMedia(rule: &RawServoMediaRule) -> Strong<RawServoMediaList>2694 pub extern "C" fn Servo_MediaRule_GetMedia(rule: &RawServoMediaRule) -> Strong<RawServoMediaList> {
2695 read_locked_arc(rule, |rule: &MediaRule| {
2696 rule.media_queries.clone().into_strong()
2697 })
2698 }
2699
2700 #[no_mangle]
Servo_NamespaceRule_GetPrefix(rule: &RawServoNamespaceRule) -> *mut nsAtom2701 pub extern "C" fn Servo_NamespaceRule_GetPrefix(rule: &RawServoNamespaceRule) -> *mut nsAtom {
2702 read_locked_arc(rule, |rule: &NamespaceRule| {
2703 rule.prefix.as_ref().unwrap_or(&atom!("")).as_ptr()
2704 })
2705 }
2706
2707 #[no_mangle]
Servo_NamespaceRule_GetURI(rule: &RawServoNamespaceRule) -> *mut nsAtom2708 pub extern "C" fn Servo_NamespaceRule_GetURI(rule: &RawServoNamespaceRule) -> *mut nsAtom {
2709 read_locked_arc(rule, |rule: &NamespaceRule| rule.url.0.as_ptr())
2710 }
2711
2712 #[no_mangle]
Servo_PageRule_GetStyle( rule: &RawServoPageRule, ) -> Strong<RawServoDeclarationBlock>2713 pub extern "C" fn Servo_PageRule_GetStyle(
2714 rule: &RawServoPageRule,
2715 ) -> Strong<RawServoDeclarationBlock> {
2716 read_locked_arc(rule, |rule: &PageRule| rule.block.clone().into_strong())
2717 }
2718
2719 #[no_mangle]
Servo_PageRule_SetStyle( rule: &RawServoPageRule, declarations: &RawServoDeclarationBlock, )2720 pub extern "C" fn Servo_PageRule_SetStyle(
2721 rule: &RawServoPageRule,
2722 declarations: &RawServoDeclarationBlock,
2723 ) {
2724 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
2725 write_locked_arc(rule, |rule: &mut PageRule| {
2726 rule.block = declarations.clone_arc();
2727 })
2728 }
2729
2730 #[no_mangle]
Servo_SupportsRule_GetConditionText( rule: &RawServoSupportsRule, result: &mut nsAString, )2731 pub extern "C" fn Servo_SupportsRule_GetConditionText(
2732 rule: &RawServoSupportsRule,
2733 result: &mut nsAString,
2734 ) {
2735 read_locked_arc(rule, |rule: &SupportsRule| {
2736 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2737 })
2738 }
2739
2740 #[no_mangle]
Servo_MozDocumentRule_GetConditionText( rule: &RawServoMozDocumentRule, result: &mut nsAString, )2741 pub extern "C" fn Servo_MozDocumentRule_GetConditionText(
2742 rule: &RawServoMozDocumentRule,
2743 result: &mut nsAString,
2744 ) {
2745 read_locked_arc(rule, |rule: &DocumentRule| {
2746 rule.condition.to_css(&mut CssWriter::new(result)).unwrap();
2747 })
2748 }
2749
2750 #[no_mangle]
Servo_FontFeatureValuesRule_GetFontFamily( rule: &RawServoFontFeatureValuesRule, result: &mut nsAString, )2751 pub extern "C" fn Servo_FontFeatureValuesRule_GetFontFamily(
2752 rule: &RawServoFontFeatureValuesRule,
2753 result: &mut nsAString,
2754 ) {
2755 read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
2756 rule.font_family_to_css(&mut CssWriter::new(result)).unwrap()
2757 })
2758 }
2759
2760 #[no_mangle]
Servo_FontFeatureValuesRule_GetValueText( rule: &RawServoFontFeatureValuesRule, result: &mut nsAString, )2761 pub extern "C" fn Servo_FontFeatureValuesRule_GetValueText(
2762 rule: &RawServoFontFeatureValuesRule,
2763 result: &mut nsAString,
2764 ) {
2765 read_locked_arc(rule, |rule: &FontFeatureValuesRule| {
2766 rule.value_to_css(&mut CssWriter::new(result)).unwrap();
2767 })
2768 }
2769
2770 #[no_mangle]
Servo_FontFaceRule_CreateEmpty() -> Strong<RawServoFontFaceRule>2771 pub extern "C" fn Servo_FontFaceRule_CreateEmpty() -> Strong<RawServoFontFaceRule> {
2772 let global_style_data = &*GLOBAL_STYLE_DATA;
2773 // XXX This is not great. We should split FontFace descriptor data
2774 // from the rule, so that we don't need to create the rule like this
2775 // and the descriptor data itself can be hold in UniquePtr from the
2776 // Gecko side. See bug 1450904.
2777 Arc::new(
2778 global_style_data
2779 .shared_lock
2780 .wrap(FontFaceRule::empty(SourceLocation { line: 0, column: 0 })),
2781 )
2782 .into_strong()
2783 }
2784
2785 #[no_mangle]
Servo_FontFaceRule_Clone( rule: &RawServoFontFaceRule, ) -> Strong<RawServoFontFaceRule>2786 pub unsafe extern "C" fn Servo_FontFaceRule_Clone(
2787 rule: &RawServoFontFaceRule,
2788 ) -> Strong<RawServoFontFaceRule> {
2789 let clone = read_locked_arc(rule, |rule: &FontFaceRule| rule.clone());
2790 let global_style_data = &*GLOBAL_STYLE_DATA;
2791 Arc::new(global_style_data.shared_lock.wrap(clone)).into_strong()
2792 }
2793
2794 #[no_mangle]
Servo_FontFaceRule_GetSourceLocation( rule: &RawServoFontFaceRule, line: *mut u32, column: *mut u32, )2795 pub unsafe extern "C" fn Servo_FontFaceRule_GetSourceLocation(
2796 rule: &RawServoFontFaceRule,
2797 line: *mut u32,
2798 column: *mut u32,
2799 ) {
2800 read_locked_arc(rule, |rule: &FontFaceRule| {
2801 let location = rule.source_location;
2802 *line.as_mut().unwrap() = location.line as u32;
2803 *column.as_mut().unwrap() = location.column as u32;
2804 });
2805 }
2806
2807 macro_rules! apply_font_desc_list {
2808 ($apply_macro:ident) => {
2809 $apply_macro! {
2810 valid: [
2811 eCSSFontDesc_Family => family,
2812 eCSSFontDesc_Style => style,
2813 eCSSFontDesc_Weight => weight,
2814 eCSSFontDesc_Stretch => stretch,
2815 eCSSFontDesc_Src => sources,
2816 eCSSFontDesc_UnicodeRange => unicode_range,
2817 eCSSFontDesc_FontFeatureSettings => feature_settings,
2818 eCSSFontDesc_FontVariationSettings => variation_settings,
2819 eCSSFontDesc_FontLanguageOverride => language_override,
2820 eCSSFontDesc_Display => display,
2821 ]
2822 invalid: [
2823 eCSSFontDesc_UNKNOWN,
2824 eCSSFontDesc_COUNT,
2825 ]
2826 }
2827 };
2828 }
2829
2830 #[no_mangle]
Servo_FontFaceRule_Length(rule: &RawServoFontFaceRule) -> u322831 pub unsafe extern "C" fn Servo_FontFaceRule_Length(rule: &RawServoFontFaceRule) -> u32 {
2832 read_locked_arc(rule, |rule: &FontFaceRule| {
2833 let mut result = 0;
2834 macro_rules! count_values {
2835 (
2836 valid: [$($v_enum_name:ident => $field:ident,)*]
2837 invalid: [$($i_enum_name:ident,)*]
2838 ) => {
2839 $(if rule.$field.is_some() {
2840 result += 1;
2841 })*
2842 }
2843 }
2844 apply_font_desc_list!(count_values);
2845 result
2846 })
2847 }
2848
2849 #[no_mangle]
Servo_FontFaceRule_IndexGetter( rule: &RawServoFontFaceRule, index: u32, ) -> nsCSSFontDesc2850 pub unsafe extern "C" fn Servo_FontFaceRule_IndexGetter(
2851 rule: &RawServoFontFaceRule,
2852 index: u32,
2853 ) -> nsCSSFontDesc {
2854 read_locked_arc(rule, |rule: &FontFaceRule| {
2855 let mut count = 0;
2856 macro_rules! lookup_index {
2857 (
2858 valid: [$($v_enum_name:ident => $field:ident,)*]
2859 invalid: [$($i_enum_name:ident,)*]
2860 ) => {
2861 $(if rule.$field.is_some() {
2862 count += 1;
2863 if count - 1 == index {
2864 return nsCSSFontDesc::$v_enum_name;
2865 }
2866 })*
2867 }
2868 }
2869 apply_font_desc_list!(lookup_index);
2870 return nsCSSFontDesc::eCSSFontDesc_UNKNOWN;
2871 })
2872 }
2873
2874 #[no_mangle]
Servo_FontFaceRule_GetDeclCssText( rule: &RawServoFontFaceRule, result: &mut nsAString, )2875 pub unsafe extern "C" fn Servo_FontFaceRule_GetDeclCssText(
2876 rule: &RawServoFontFaceRule,
2877 result: &mut nsAString,
2878 ) {
2879 read_locked_arc(rule, |rule: &FontFaceRule| {
2880 rule.decl_to_css(result).unwrap();
2881 })
2882 }
2883
2884 macro_rules! simple_font_descriptor_getter_impl {
2885 ($rule:ident, $out:ident, $field:ident, $compute:ident) => {
2886 read_locked_arc($rule, |rule: &FontFaceRule| {
2887 match rule.$field {
2888 None => return false,
2889 Some(ref f) => *$out = f.$compute(),
2890 }
2891 true
2892 })
2893 };
2894 }
2895
2896 #[no_mangle]
Servo_FontFaceRule_GetFontWeight( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontWeightRange, ) -> bool2897 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontWeight(
2898 rule: &RawServoFontFaceRule,
2899 out: &mut font_face::ComputedFontWeightRange,
2900 ) -> bool {
2901 simple_font_descriptor_getter_impl!(rule, out, weight, compute)
2902 }
2903
2904 #[no_mangle]
Servo_FontFaceRule_GetFontStretch( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontStretchRange, ) -> bool2905 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStretch(
2906 rule: &RawServoFontFaceRule,
2907 out: &mut font_face::ComputedFontStretchRange,
2908 ) -> bool {
2909 simple_font_descriptor_getter_impl!(rule, out, stretch, compute)
2910 }
2911
2912 #[no_mangle]
Servo_FontFaceRule_GetFontStyle( rule: &RawServoFontFaceRule, out: &mut font_face::ComputedFontStyleDescriptor, ) -> bool2913 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontStyle(
2914 rule: &RawServoFontFaceRule,
2915 out: &mut font_face::ComputedFontStyleDescriptor,
2916 ) -> bool {
2917 simple_font_descriptor_getter_impl!(rule, out, style, compute)
2918 }
2919
2920 #[no_mangle]
Servo_FontFaceRule_GetFontDisplay( rule: &RawServoFontFaceRule, out: &mut font_face::FontDisplay, ) -> bool2921 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontDisplay(
2922 rule: &RawServoFontFaceRule,
2923 out: &mut font_face::FontDisplay,
2924 ) -> bool {
2925 simple_font_descriptor_getter_impl!(rule, out, display, clone)
2926 }
2927
2928 #[no_mangle]
Servo_FontFaceRule_GetFontLanguageOverride( rule: &RawServoFontFaceRule, out: &mut computed::FontLanguageOverride, ) -> bool2929 pub unsafe extern "C" fn Servo_FontFaceRule_GetFontLanguageOverride(
2930 rule: &RawServoFontFaceRule,
2931 out: &mut computed::FontLanguageOverride,
2932 ) -> bool {
2933 simple_font_descriptor_getter_impl!(rule, out, language_override, compute_non_system)
2934 }
2935
2936 #[no_mangle]
Servo_FontFaceRule_GetFamilyName( rule: &RawServoFontFaceRule, ) -> *mut nsAtom2937 pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
2938 rule: &RawServoFontFaceRule,
2939 ) -> *mut nsAtom {
2940 read_locked_arc(rule, |rule: &FontFaceRule| {
2941 // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
2942 // here, and remove the null-checks in Gecko?
2943 rule.family
2944 .as_ref()
2945 .map_or(ptr::null_mut(), |f| f.name.as_ptr())
2946 })
2947 }
2948
2949 #[no_mangle]
Servo_FontFaceRule_GetUnicodeRanges( rule: &RawServoFontFaceRule, out_len: *mut usize, ) -> *const UnicodeRange2950 pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
2951 rule: &RawServoFontFaceRule,
2952 out_len: *mut usize,
2953 ) -> *const UnicodeRange {
2954 *out_len = 0;
2955 read_locked_arc(rule, |rule: &FontFaceRule| {
2956 let ranges = match rule.unicode_range {
2957 Some(ref ranges) => ranges,
2958 None => return ptr::null(),
2959 };
2960 *out_len = ranges.len();
2961 ranges.as_ptr() as *const _
2962 })
2963 }
2964
2965 #[no_mangle]
Servo_FontFaceRule_GetSources( rule: &RawServoFontFaceRule, out: *mut nsTArray<FontFaceSourceListComponent>, )2966 pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
2967 rule: &RawServoFontFaceRule,
2968 out: *mut nsTArray<FontFaceSourceListComponent>,
2969 ) {
2970 let out = &mut *out;
2971 read_locked_arc(rule, |rule: &FontFaceRule| {
2972 let sources = match rule.sources {
2973 Some(ref s) => s,
2974 None => return,
2975 };
2976 let len = sources.iter().fold(0, |acc, src| {
2977 acc + match *src {
2978 // Each format hint takes one position in the array of mSrc.
2979 Source::Url(ref url) => url.format_hints.len() + 1,
2980 Source::Local(_) => 1,
2981 }
2982 });
2983
2984 out.set_len(len as u32);
2985
2986 let mut iter = out.iter_mut();
2987
2988 {
2989 let mut set_next = |component: FontFaceSourceListComponent| {
2990 *iter.next().expect("miscalculated length") = component;
2991 };
2992
2993 for source in sources.iter() {
2994 match *source {
2995 Source::Url(ref url) => {
2996 set_next(FontFaceSourceListComponent::Url(&url.url));
2997 for hint in url.format_hints.iter() {
2998 set_next(FontFaceSourceListComponent::FormatHint {
2999 length: hint.len(),
3000 utf8_bytes: hint.as_ptr(),
3001 });
3002 }
3003 },
3004 Source::Local(ref name) => {
3005 set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
3006 },
3007 }
3008 }
3009 }
3010
3011 assert!(iter.next().is_none(), "miscalculated");
3012 })
3013 }
3014
3015 #[no_mangle]
Servo_FontFaceRule_GetVariationSettings( rule: &RawServoFontFaceRule, variations: *mut nsTArray<structs::gfxFontVariation>, )3016 pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
3017 rule: &RawServoFontFaceRule,
3018 variations: *mut nsTArray<structs::gfxFontVariation>,
3019 ) {
3020 read_locked_arc(rule, |rule: &FontFaceRule| {
3021 let source_variations = match rule.variation_settings {
3022 Some(ref v) => v,
3023 None => return,
3024 };
3025
3026 (*variations).set_len(source_variations.0.len() as u32);
3027 for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
3028 *target = structs::gfxFontVariation {
3029 mTag: source.tag.0,
3030 mValue: source.value.get(),
3031 };
3032 }
3033 });
3034 }
3035
3036 #[no_mangle]
Servo_FontFaceRule_GetFeatureSettings( rule: &RawServoFontFaceRule, features: *mut nsTArray<structs::gfxFontFeature>, )3037 pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
3038 rule: &RawServoFontFaceRule,
3039 features: *mut nsTArray<structs::gfxFontFeature>,
3040 ) {
3041 read_locked_arc(rule, |rule: &FontFaceRule| {
3042 let source_features = match rule.feature_settings {
3043 Some(ref v) => v,
3044 None => return,
3045 };
3046
3047 (*features).set_len(source_features.0.len() as u32);
3048 for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
3049 *target = structs::gfxFontFeature {
3050 mTag: source.tag.0,
3051 mValue: source.value.value() as u32,
3052 };
3053 }
3054 });
3055 }
3056
3057 #[no_mangle]
Servo_FontFaceRule_GetDescriptorCssText( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, result: &mut nsAString, )3058 pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
3059 rule: &RawServoFontFaceRule,
3060 desc: nsCSSFontDesc,
3061 result: &mut nsAString,
3062 ) {
3063 read_locked_arc(rule, |rule: &FontFaceRule| {
3064 let mut writer = CssWriter::new(result);
3065 macro_rules! to_css_text {
3066 (
3067 valid: [$($v_enum_name:ident => $field:ident,)*]
3068 invalid: [$($i_enum_name:ident,)*]
3069 ) => {
3070 match desc {
3071 $(
3072 nsCSSFontDesc::$v_enum_name => {
3073 if let Some(ref value) = rule.$field {
3074 value.to_css(&mut writer).unwrap();
3075 }
3076 }
3077 )*
3078 $(
3079 nsCSSFontDesc::$i_enum_name => {
3080 debug_assert!(false, "not a valid font descriptor");
3081 }
3082 )*
3083 }
3084 }
3085 }
3086 apply_font_desc_list!(to_css_text)
3087 })
3088 }
3089
3090 #[no_mangle]
Servo_FontFaceRule_SetDescriptor( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, value: &nsACString, data: *mut URLExtraData, out_changed: *mut bool, ) -> bool3091 pub unsafe extern "C" fn Servo_FontFaceRule_SetDescriptor(
3092 rule: &RawServoFontFaceRule,
3093 desc: nsCSSFontDesc,
3094 value: &nsACString,
3095 data: *mut URLExtraData,
3096 out_changed: *mut bool,
3097 ) -> bool {
3098 let value = value.as_str_unchecked();
3099 let mut input = ParserInput::new(&value);
3100 let mut parser = Parser::new(&mut input);
3101 let url_data = UrlExtraData::from_ptr_ref(&data);
3102 let context = ParserContext::new(
3103 Origin::Author,
3104 url_data,
3105 Some(CssRuleType::FontFace),
3106 ParsingMode::DEFAULT,
3107 QuirksMode::NoQuirks,
3108 None,
3109 None,
3110 );
3111
3112 write_locked_arc(rule, |rule: &mut FontFaceRule| {
3113 macro_rules! to_css_text {
3114 (
3115 valid: [$($v_enum_name:ident => $field:ident,)*]
3116 invalid: [$($i_enum_name:ident,)*]
3117 ) => {
3118 match desc {
3119 $(
3120 nsCSSFontDesc::$v_enum_name => {
3121 if let Ok(value) = parser.parse_entirely(|i| Parse::parse(&context, i)) {
3122 let result = Some(value);
3123 *out_changed = result != rule.$field;
3124 rule.$field = result;
3125 true
3126 } else {
3127 false
3128 }
3129 }
3130 )*
3131 $(
3132 nsCSSFontDesc::$i_enum_name => {
3133 debug_assert!(false, "not a valid font descriptor");
3134 false
3135 }
3136 )*
3137 }
3138 }
3139 }
3140 apply_font_desc_list!(to_css_text)
3141 })
3142 }
3143
3144 #[no_mangle]
Servo_FontFaceRule_ResetDescriptor( rule: &RawServoFontFaceRule, desc: nsCSSFontDesc, )3145 pub unsafe extern "C" fn Servo_FontFaceRule_ResetDescriptor(
3146 rule: &RawServoFontFaceRule,
3147 desc: nsCSSFontDesc,
3148 ) {
3149 write_locked_arc(rule, |rule: &mut FontFaceRule| {
3150 macro_rules! reset_desc {
3151 (
3152 valid: [$($v_enum_name:ident => $field:ident,)*]
3153 invalid: [$($i_enum_name:ident,)*]
3154 ) => {
3155 match desc {
3156 $(nsCSSFontDesc::$v_enum_name => rule.$field = None,)*
3157 $(nsCSSFontDesc::$i_enum_name => debug_assert!(false, "not a valid font descriptor"),)*
3158 }
3159 }
3160 }
3161 apply_font_desc_list!(reset_desc)
3162 })
3163 }
3164
3165 #[no_mangle]
Servo_CounterStyleRule_GetName( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3166 pub unsafe extern "C" fn Servo_CounterStyleRule_GetName(
3167 rule: &RawServoCounterStyleRule,
3168 ) -> *mut nsAtom {
3169 read_locked_arc(rule, |rule: &CounterStyleRule| rule.name().0.as_ptr())
3170 }
3171
3172 #[no_mangle]
Servo_CounterStyleRule_SetName( rule: &RawServoCounterStyleRule, value: &nsACString, ) -> bool3173 pub unsafe extern "C" fn Servo_CounterStyleRule_SetName(
3174 rule: &RawServoCounterStyleRule,
3175 value: &nsACString,
3176 ) -> bool {
3177 let value = value.as_str_unchecked();
3178 let mut input = ParserInput::new(&value);
3179 let mut parser = Parser::new(&mut input);
3180 match parser.parse_entirely(counter_style::parse_counter_style_name_definition) {
3181 Ok(name) => {
3182 write_locked_arc(rule, |rule: &mut CounterStyleRule| rule.set_name(name));
3183 true
3184 },
3185 Err(_) => false,
3186 }
3187 }
3188
3189 #[no_mangle]
Servo_CounterStyleRule_GetGeneration( rule: &RawServoCounterStyleRule, ) -> u323190 pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
3191 rule: &RawServoCounterStyleRule,
3192 ) -> u32 {
3193 read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
3194 }
3195
symbol_to_string(s: &counter_style::Symbol) -> nsString3196 fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
3197 match *s {
3198 counter_style::Symbol::String(ref s) => nsString::from(&**s),
3199 counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice()),
3200 }
3201 }
3202
3203 // TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
3204 #[no_mangle]
Servo_CounterStyleRule_GetPad( rule: &RawServoCounterStyleRule, width: &mut i32, symbol: &mut nsString, ) -> bool3205 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
3206 rule: &RawServoCounterStyleRule,
3207 width: &mut i32,
3208 symbol: &mut nsString,
3209 ) -> bool {
3210 read_locked_arc(rule, |rule: &CounterStyleRule| {
3211 let pad = match rule.pad() {
3212 Some(pad) => pad,
3213 None => return false,
3214 };
3215 *width = pad.0.value();
3216 *symbol = symbol_to_string(&pad.1);
3217 true
3218 })
3219 }
3220
get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool3221 fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
3222 let s = match s {
3223 Some(s) => s,
3224 None => return false,
3225 };
3226 *out = symbol_to_string(s);
3227 true
3228 }
3229
3230 #[no_mangle]
Servo_CounterStyleRule_GetPrefix( rule: &RawServoCounterStyleRule, out: &mut nsString, ) -> bool3231 pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
3232 rule: &RawServoCounterStyleRule,
3233 out: &mut nsString,
3234 ) -> bool {
3235 read_locked_arc(rule, |rule: &CounterStyleRule| {
3236 get_symbol(rule.prefix(), out)
3237 })
3238 }
3239
3240 #[no_mangle]
Servo_CounterStyleRule_GetSuffix( rule: &RawServoCounterStyleRule, out: &mut nsString, ) -> bool3241 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
3242 rule: &RawServoCounterStyleRule,
3243 out: &mut nsString,
3244 ) -> bool {
3245 read_locked_arc(rule, |rule: &CounterStyleRule| {
3246 get_symbol(rule.suffix(), out)
3247 })
3248 }
3249
3250 #[no_mangle]
Servo_CounterStyleRule_GetNegative( rule: &RawServoCounterStyleRule, prefix: &mut nsString, suffix: &mut nsString, ) -> bool3251 pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
3252 rule: &RawServoCounterStyleRule,
3253 prefix: &mut nsString,
3254 suffix: &mut nsString,
3255 ) -> bool {
3256 read_locked_arc(rule, |rule: &CounterStyleRule| {
3257 let negative = match rule.negative() {
3258 Some(n) => n,
3259 None => return false,
3260 };
3261 *prefix = symbol_to_string(&negative.0);
3262 *suffix = match negative.1 {
3263 Some(ref s) => symbol_to_string(s),
3264 None => nsString::new(),
3265 };
3266 true
3267 })
3268 }
3269
3270 #[repr(u8)]
3271 pub enum IsOrdinalInRange {
3272 Auto,
3273 InRange,
3274 NotInRange,
3275 NoOrdinalSpecified,
3276 }
3277
3278 #[no_mangle]
Servo_CounterStyleRule_IsInRange( rule: &RawServoCounterStyleRule, ordinal: i32, ) -> IsOrdinalInRange3279 pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
3280 rule: &RawServoCounterStyleRule,
3281 ordinal: i32,
3282 ) -> IsOrdinalInRange {
3283 use style::counter_style::CounterBound;
3284 read_locked_arc(rule, |rule: &CounterStyleRule| {
3285 let range = match rule.range() {
3286 Some(r) => r,
3287 None => return IsOrdinalInRange::NoOrdinalSpecified,
3288 };
3289
3290 if range.0.is_empty() {
3291 return IsOrdinalInRange::Auto;
3292 }
3293
3294 let in_range = range.0.iter().any(|r| {
3295 if let CounterBound::Integer(start) = r.start {
3296 if start.value() > ordinal {
3297 return false;
3298 }
3299 }
3300
3301 if let CounterBound::Integer(end) = r.end {
3302 if end.value() < ordinal {
3303 return false;
3304 }
3305 }
3306
3307 true
3308 });
3309
3310 if in_range {
3311 IsOrdinalInRange::InRange
3312 } else {
3313 IsOrdinalInRange::NotInRange
3314 }
3315 })
3316 }
3317
3318 #[no_mangle]
Servo_CounterStyleRule_GetSymbols( rule: &RawServoCounterStyleRule, symbols: &mut style::OwnedSlice<nsString>, )3319 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
3320 rule: &RawServoCounterStyleRule,
3321 symbols: &mut style::OwnedSlice<nsString>,
3322 ) {
3323 read_locked_arc(rule, |rule: &CounterStyleRule| {
3324 *symbols = match rule.symbols() {
3325 Some(s) => s.0.iter().map(symbol_to_string).collect(),
3326 None => style::OwnedSlice::default(),
3327 };
3328 })
3329 }
3330
3331 #[repr(C)]
3332 pub struct AdditiveSymbol {
3333 pub weight: i32,
3334 pub symbol: nsString,
3335 }
3336
3337 #[no_mangle]
Servo_CounterStyleRule_GetAdditiveSymbols( rule: &RawServoCounterStyleRule, symbols: &mut style::OwnedSlice<AdditiveSymbol>, )3338 pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
3339 rule: &RawServoCounterStyleRule,
3340 symbols: &mut style::OwnedSlice<AdditiveSymbol>,
3341 ) {
3342 read_locked_arc(rule, |rule: &CounterStyleRule| {
3343 *symbols = match rule.additive_symbols() {
3344 Some(s) => {
3345 s.0.iter()
3346 .map(|s| AdditiveSymbol {
3347 weight: s.weight.value(),
3348 symbol: symbol_to_string(&s.symbol),
3349 })
3350 .collect()
3351 },
3352 None => style::OwnedSlice::default(),
3353 };
3354 })
3355 }
3356
3357 #[repr(C, u8)]
3358 pub enum CounterSpeakAs {
3359 None,
3360 Auto,
3361 Bullets,
3362 Numbers,
3363 Words,
3364 Ident(*mut nsAtom),
3365 }
3366
3367 #[no_mangle]
Servo_CounterStyleRule_GetSpeakAs( rule: &RawServoCounterStyleRule, out: &mut CounterSpeakAs, )3368 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
3369 rule: &RawServoCounterStyleRule,
3370 out: &mut CounterSpeakAs,
3371 ) {
3372 use style::counter_style::SpeakAs;
3373 *out = read_locked_arc(rule, |rule: &CounterStyleRule| {
3374 let speak_as = match rule.speak_as() {
3375 Some(s) => s,
3376 None => return CounterSpeakAs::None,
3377 };
3378 match *speak_as {
3379 SpeakAs::Auto => CounterSpeakAs::Auto,
3380 SpeakAs::Bullets => CounterSpeakAs::Bullets,
3381 SpeakAs::Numbers => CounterSpeakAs::Numbers,
3382 SpeakAs::Words => CounterSpeakAs::Words,
3383 SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
3384 }
3385 });
3386 }
3387
3388 #[repr(u8)]
3389 pub enum CounterSystem {
3390 Cyclic = 0,
3391 Numeric,
3392 Alphabetic,
3393 Symbolic,
3394 Additive,
3395 Fixed,
3396 Extends
3397 }
3398
3399 #[no_mangle]
Servo_CounterStyleRule_GetSystem( rule: &RawServoCounterStyleRule ) -> CounterSystem3400 pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
3401 rule: &RawServoCounterStyleRule
3402 ) -> CounterSystem {
3403 use style::counter_style::System;
3404 read_locked_arc(rule, |rule: &CounterStyleRule| {
3405 match *rule.resolved_system() {
3406 System::Cyclic => CounterSystem::Cyclic,
3407 System::Numeric => CounterSystem::Numeric,
3408 System::Alphabetic => CounterSystem::Alphabetic,
3409 System::Symbolic => CounterSystem::Symbolic,
3410 System::Additive => CounterSystem::Additive,
3411 System::Fixed { .. } => CounterSystem::Fixed,
3412 System::Extends(_) => CounterSystem::Extends,
3413 }
3414 })
3415 }
3416
3417 #[no_mangle]
Servo_CounterStyleRule_GetExtended( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3418 pub unsafe extern "C" fn Servo_CounterStyleRule_GetExtended(
3419 rule: &RawServoCounterStyleRule,
3420 ) -> *mut nsAtom {
3421 read_locked_arc(rule, |rule: &CounterStyleRule| {
3422 match *rule.resolved_system() {
3423 counter_style::System::Extends(ref name) => name.0.as_ptr(),
3424 _ => {
3425 debug_assert!(false, "Not extends system");
3426 ptr::null_mut()
3427 },
3428 }
3429 })
3430 }
3431
3432 #[no_mangle]
Servo_CounterStyleRule_GetFixedFirstValue( rule: &RawServoCounterStyleRule, ) -> i323433 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFixedFirstValue(
3434 rule: &RawServoCounterStyleRule,
3435 ) -> i32 {
3436 read_locked_arc(rule, |rule: &CounterStyleRule| {
3437 match *rule.resolved_system() {
3438 counter_style::System::Fixed { first_symbol_value } => {
3439 first_symbol_value.map_or(1, |v| v.value())
3440 },
3441 _ => {
3442 debug_assert!(false, "Not fixed system");
3443 0
3444 },
3445 }
3446 })
3447 }
3448
3449 #[no_mangle]
Servo_CounterStyleRule_GetFallback( rule: &RawServoCounterStyleRule, ) -> *mut nsAtom3450 pub unsafe extern "C" fn Servo_CounterStyleRule_GetFallback(
3451 rule: &RawServoCounterStyleRule,
3452 ) -> *mut nsAtom {
3453 read_locked_arc(rule, |rule: &CounterStyleRule| {
3454 rule.fallback().map_or(ptr::null_mut(), |i| i.0 .0.as_ptr())
3455 })
3456 }
3457
3458 macro_rules! counter_style_descriptors {
3459 {
3460 valid: [
3461 $($desc:ident => $getter:ident / $setter:ident,)+
3462 ]
3463 invalid: [
3464 $($i_desc:ident,)+
3465 ]
3466 } => {
3467 #[no_mangle]
3468 pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
3469 rule: &RawServoCounterStyleRule,
3470 desc: nsCSSCounterDesc,
3471 result: &mut nsAString,
3472 ) {
3473 let mut writer = CssWriter::new(result);
3474 read_locked_arc(rule, |rule: &CounterStyleRule| {
3475 match desc {
3476 $(nsCSSCounterDesc::$desc => {
3477 if let Some(value) = rule.$getter() {
3478 value.to_css(&mut writer).unwrap();
3479 }
3480 })+
3481 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3482 }
3483 });
3484 }
3485
3486 #[no_mangle]
3487 pub unsafe extern "C" fn Servo_CounterStyleRule_SetDescriptor(
3488 rule: &RawServoCounterStyleRule,
3489 desc: nsCSSCounterDesc,
3490 value: &nsACString,
3491 ) -> bool {
3492 let value = value.as_str_unchecked();
3493 let mut input = ParserInput::new(&value);
3494 let mut parser = Parser::new(&mut input);
3495 let url_data = dummy_url_data();
3496 let context = ParserContext::new(
3497 Origin::Author,
3498 url_data,
3499 Some(CssRuleType::CounterStyle),
3500 ParsingMode::DEFAULT,
3501 QuirksMode::NoQuirks,
3502 None,
3503 None,
3504 );
3505
3506 write_locked_arc(rule, |rule: &mut CounterStyleRule| {
3507 match desc {
3508 $(nsCSSCounterDesc::$desc => {
3509 match parser.parse_entirely(|i| Parse::parse(&context, i)) {
3510 Ok(value) => rule.$setter(value),
3511 Err(_) => false,
3512 }
3513 })+
3514 $(nsCSSCounterDesc::$i_desc => unreachable!(),)+
3515 }
3516 })
3517 }
3518 }
3519 }
3520
3521 counter_style_descriptors! {
3522 valid: [
3523 eCSSCounterDesc_System => system / set_system,
3524 eCSSCounterDesc_Symbols => symbols / set_symbols,
3525 eCSSCounterDesc_AdditiveSymbols => additive_symbols / set_additive_symbols,
3526 eCSSCounterDesc_Negative => negative / set_negative,
3527 eCSSCounterDesc_Prefix => prefix / set_prefix,
3528 eCSSCounterDesc_Suffix => suffix / set_suffix,
3529 eCSSCounterDesc_Range => range / set_range,
3530 eCSSCounterDesc_Pad => pad / set_pad,
3531 eCSSCounterDesc_Fallback => fallback / set_fallback,
3532 eCSSCounterDesc_SpeakAs => speak_as / set_speak_as,
3533 ]
3534 invalid: [
3535 eCSSCounterDesc_UNKNOWN,
3536 eCSSCounterDesc_COUNT,
3537 ]
3538 }
3539
3540 #[no_mangle]
Servo_ComputedValues_GetForAnonymousBox( parent_style_or_null: Option<&ComputedValues>, pseudo: PseudoStyleType, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3541 pub unsafe extern "C" fn Servo_ComputedValues_GetForAnonymousBox(
3542 parent_style_or_null: Option<&ComputedValues>,
3543 pseudo: PseudoStyleType,
3544 raw_data: &RawServoStyleSet,
3545 ) -> Strong<ComputedValues> {
3546 let global_style_data = &*GLOBAL_STYLE_DATA;
3547 let guard = global_style_data.shared_lock.read();
3548 let guards = StylesheetGuards::same(&guard);
3549 let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
3550 let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
3551 debug_assert!(pseudo.is_anon_box());
3552
3553 let metrics = get_metrics_provider_for_product();
3554
3555 // If the pseudo element is PageContent, we should append the precomputed
3556 // pseudo element declerations with specified page rules.
3557 let page_decls = match pseudo {
3558 PseudoElement::PageContent => {
3559 let mut declarations = vec![];
3560 let iter = data.stylist.iter_extra_data_origins_rev();
3561 for (data, origin) in iter {
3562 let level = match origin {
3563 Origin::UserAgent => CascadeLevel::UANormal,
3564 Origin::User => CascadeLevel::UserNormal,
3565 Origin::Author => CascadeLevel::same_tree_author_normal(),
3566 };
3567 for rule in data.pages.iter() {
3568 declarations.push(ApplicableDeclarationBlock::from_declarations(
3569 rule.read_with(level.guard(&guards)).block.clone(),
3570 level,
3571 ));
3572 }
3573 }
3574 Some(declarations)
3575 },
3576 _ => None,
3577 };
3578
3579 let rule_node = data
3580 .stylist
3581 .rule_node_for_precomputed_pseudo(&guards, &pseudo, page_decls);
3582
3583 data.stylist
3584 .precomputed_values_for_pseudo_with_rule_node::<GeckoElement>(
3585 &guards,
3586 &pseudo,
3587 parent_style_or_null.map(|x| &*x),
3588 &metrics,
3589 rule_node,
3590 )
3591 .into()
3592 }
3593
3594 #[no_mangle]
Servo_ResolvePseudoStyle( element: &RawGeckoElement, pseudo_type: PseudoStyleType, is_probe: bool, inherited_style: Option<&ComputedValues>, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3595 pub extern "C" fn Servo_ResolvePseudoStyle(
3596 element: &RawGeckoElement,
3597 pseudo_type: PseudoStyleType,
3598 is_probe: bool,
3599 inherited_style: Option<&ComputedValues>,
3600 raw_data: &RawServoStyleSet,
3601 ) -> Strong<ComputedValues> {
3602 let element = GeckoElement(element);
3603 let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3604
3605 debug!(
3606 "Servo_ResolvePseudoStyle: {:?} {:?}, is_probe: {}",
3607 element,
3608 PseudoElement::from_pseudo_type(pseudo_type),
3609 is_probe
3610 );
3611
3612 let data = element.borrow_data();
3613
3614 let data = match data.as_ref() {
3615 Some(data) if data.has_styles() => data,
3616 _ => {
3617 // FIXME(bholley, emilio): Assert against this.
3618 //
3619 // Known offender is nsMathMLmoFrame::MarkIntrinsicISizesDirty,
3620 // which goes and does a bunch of work involving style resolution.
3621 //
3622 // Bug 1403865 tracks fixing it, and potentially adding an assert
3623 // here instead.
3624 warn!("Calling Servo_ResolvePseudoStyle on unstyled element");
3625 return if is_probe {
3626 Strong::null()
3627 } else {
3628 doc_data.default_computed_values().clone().into()
3629 };
3630 },
3631 };
3632
3633 let pseudo = PseudoElement::from_pseudo_type(pseudo_type)
3634 .expect("ResolvePseudoStyle with a non-pseudo?");
3635
3636 let global_style_data = &*GLOBAL_STYLE_DATA;
3637 let guard = global_style_data.shared_lock.read();
3638 let style = get_pseudo_style(
3639 &guard,
3640 element,
3641 &pseudo,
3642 RuleInclusion::All,
3643 &data.styles,
3644 inherited_style,
3645 &*doc_data,
3646 is_probe,
3647 /* matching_func = */ None,
3648 );
3649
3650 match style {
3651 Some(s) => s.into(),
3652 None => {
3653 debug_assert!(is_probe);
3654 Strong::null()
3655 },
3656 }
3657 }
3658
debug_atom_array(atoms: &AtomArray) -> String3659 fn debug_atom_array(atoms: &AtomArray) -> String {
3660 let mut result = String::from("[");
3661 for atom in atoms.iter() {
3662 if atom.mRawPtr.is_null() {
3663 result += "(null), ";
3664 } else {
3665 let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
3666 write!(result, "{}, ", atom).unwrap();
3667 }
3668 }
3669 result.push(']');
3670 result
3671 }
3672
3673 #[no_mangle]
Servo_ComputedValues_ResolveXULTreePseudoStyle( element: &RawGeckoElement, pseudo_tag: *mut nsAtom, inherited_style: &ComputedValues, input_word: &AtomArray, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>3674 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
3675 element: &RawGeckoElement,
3676 pseudo_tag: *mut nsAtom,
3677 inherited_style: &ComputedValues,
3678 input_word: &AtomArray,
3679 raw_data: &RawServoStyleSet,
3680 ) -> Strong<ComputedValues> {
3681 let element = GeckoElement(element);
3682 let data = element
3683 .borrow_data()
3684 .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
3685
3686 let pseudo = unsafe {
3687 Atom::with(pseudo_tag, |atom| {
3688 PseudoElement::from_tree_pseudo_atom(atom, Box::new([]))
3689 })
3690 .expect("ResolveXULTreePseudoStyle with a non-tree pseudo?")
3691 };
3692 let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3693
3694 debug!(
3695 "ResolveXULTreePseudoStyle: {:?} {:?} {}",
3696 element,
3697 pseudo,
3698 debug_atom_array(input_word)
3699 );
3700
3701 let matching_fn = |pseudo: &PseudoElement| {
3702 let args = pseudo
3703 .tree_pseudo_args()
3704 .expect("Not a tree pseudo-element?");
3705 args.iter()
3706 .all(|atom| input_word.iter().any(|item| atom.as_ptr() == item.mRawPtr))
3707 };
3708
3709 let global_style_data = &*GLOBAL_STYLE_DATA;
3710 let guard = global_style_data.shared_lock.read();
3711 get_pseudo_style(
3712 &guard,
3713 element,
3714 &pseudo,
3715 RuleInclusion::All,
3716 &data.styles,
3717 Some(inherited_style),
3718 &*doc_data,
3719 /* is_probe = */ false,
3720 Some(&matching_fn),
3721 )
3722 .unwrap()
3723 .into()
3724 }
3725
3726 #[no_mangle]
Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues)3727 pub extern "C" fn Servo_SetExplicitStyle(element: &RawGeckoElement, style: &ComputedValues) {
3728 let element = GeckoElement(element);
3729 debug!("Servo_SetExplicitStyle: {:?}", element);
3730 // We only support this API for initial styling. There's no reason it couldn't
3731 // work for other things, we just haven't had a reason to do so.
3732 debug_assert!(!element.has_data());
3733 let mut data = unsafe { element.ensure_data() };
3734 data.styles.primary = Some(unsafe { ArcBorrow::from_ref(style) }.clone_arc());
3735 }
3736
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>>3737 fn get_pseudo_style(
3738 guard: &SharedRwLockReadGuard,
3739 element: GeckoElement,
3740 pseudo: &PseudoElement,
3741 rule_inclusion: RuleInclusion,
3742 styles: &ElementStyles,
3743 inherited_styles: Option<&ComputedValues>,
3744 doc_data: &PerDocumentStyleDataImpl,
3745 is_probe: bool,
3746 matching_func: Option<&dyn Fn(&PseudoElement) -> bool>,
3747 ) -> Option<Arc<ComputedValues>> {
3748 let style = match pseudo.cascade_type() {
3749 PseudoElementCascadeType::Eager => {
3750 match *pseudo {
3751 PseudoElement::FirstLetter => {
3752 styles.pseudos.get(&pseudo).map(|pseudo_styles| {
3753 // inherited_styles can be None when doing lazy resolution
3754 // (e.g. for computed style) or when probing. In that case
3755 // we just inherit from our element, which is what Gecko
3756 // does in that situation. What should actually happen in
3757 // the computed style case is a bit unclear.
3758 let inherited_styles = inherited_styles.unwrap_or(styles.primary());
3759 let guards = StylesheetGuards::same(guard);
3760 let metrics = get_metrics_provider_for_product();
3761 let inputs = CascadeInputs::new_from_style(pseudo_styles);
3762 doc_data.stylist.compute_pseudo_element_style_with_inputs(
3763 inputs,
3764 pseudo,
3765 &guards,
3766 Some(inherited_styles),
3767 &metrics,
3768 Some(element),
3769 )
3770 })
3771 },
3772 _ => {
3773 // Unfortunately, we can't assert that inherited_styles, if
3774 // present, is pointer-equal to styles.primary(), or even
3775 // equal in any meaningful way. The way it can fail is as
3776 // follows. Say we append an element with a ::before,
3777 // ::after, or ::first-line to a parent with a ::first-line,
3778 // such that the element ends up on the first line of the
3779 // parent (e.g. it's an inline-block in the case it has a
3780 // ::first-line, or any container in the ::before/::after
3781 // cases). Then gecko will update its frame's style to
3782 // inherit from the parent's ::first-line. The next time we
3783 // try to get the ::before/::after/::first-line style for
3784 // the kid, we'll likely pass in the frame's style as
3785 // inherited_styles, but that's not pointer-identical to
3786 // styles.primary(), because it got reparented.
3787 //
3788 // Now in practice this turns out to be OK, because all the
3789 // cases in which there's a mismatch go ahead and reparent
3790 // styles again as needed to make sure the ::first-line
3791 // affects all the things it should affect. But it makes it
3792 // impossible to assert anything about the two styles
3793 // matching here, unfortunately.
3794 styles.pseudos.get(&pseudo).cloned()
3795 },
3796 }
3797 },
3798 PseudoElementCascadeType::Precomputed => unreachable!("No anonymous boxes"),
3799 PseudoElementCascadeType::Lazy => {
3800 debug_assert!(
3801 inherited_styles.is_none() ||
3802 ptr::eq(inherited_styles.unwrap(), &**styles.primary())
3803 );
3804 let base = if pseudo.inherits_from_default_values() {
3805 doc_data.default_computed_values()
3806 } else {
3807 styles.primary()
3808 };
3809 let guards = StylesheetGuards::same(guard);
3810 let metrics = get_metrics_provider_for_product();
3811 doc_data.stylist.lazily_compute_pseudo_element_style(
3812 &guards,
3813 element,
3814 &pseudo,
3815 rule_inclusion,
3816 base,
3817 is_probe,
3818 &metrics,
3819 matching_func,
3820 )
3821 },
3822 };
3823
3824 if is_probe {
3825 return style;
3826 }
3827
3828 Some(style.unwrap_or_else(|| {
3829 StyleBuilder::for_inheritance(
3830 doc_data.stylist.device(),
3831 Some(styles.primary()),
3832 Some(pseudo),
3833 )
3834 .build()
3835 }))
3836 }
3837
3838 #[no_mangle]
Servo_ComputedValues_Inherit( raw_data: &RawServoStyleSet, pseudo: PseudoStyleType, parent_style_context: Option<&ComputedValues>, target: structs::InheritTarget, ) -> Strong<ComputedValues>3839 pub unsafe extern "C" fn Servo_ComputedValues_Inherit(
3840 raw_data: &RawServoStyleSet,
3841 pseudo: PseudoStyleType,
3842 parent_style_context: Option<&ComputedValues>,
3843 target: structs::InheritTarget,
3844 ) -> Strong<ComputedValues> {
3845 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
3846
3847 let for_text = target == structs::InheritTarget::Text;
3848 let pseudo = PseudoElement::from_pseudo_type(pseudo).unwrap();
3849 debug_assert!(pseudo.is_anon_box());
3850
3851 let mut style =
3852 StyleBuilder::for_inheritance(data.stylist.device(), parent_style_context, Some(&pseudo));
3853
3854 if for_text {
3855 StyleAdjuster::new(&mut style).adjust_for_text();
3856 }
3857
3858 style.build().into()
3859 }
3860
3861 #[no_mangle]
Servo_ComputedValues_SpecifiesAnimationsOrTransitions( values: &ComputedValues, ) -> bool3862 pub extern "C" fn Servo_ComputedValues_SpecifiesAnimationsOrTransitions(
3863 values: &ComputedValues,
3864 ) -> bool {
3865 let b = values.get_box();
3866 b.specifies_animations() || b.specifies_transitions()
3867 }
3868
3869 #[no_mangle]
Servo_ComputedValues_GetStyleRuleList( values: &ComputedValues, rules: &mut nsTArray<*const RawServoStyleRule>, )3870 pub extern "C" fn Servo_ComputedValues_GetStyleRuleList(
3871 values: &ComputedValues,
3872 rules: &mut nsTArray<*const RawServoStyleRule>,
3873 ) {
3874 let rule_node = match values.rules {
3875 Some(ref r) => r,
3876 None => return,
3877 };
3878
3879 let mut result = SmallVec::<[_; 10]>::new();
3880 for node in rule_node.self_and_ancestors() {
3881 let style_rule = match node.style_source().and_then(|x| x.as_rule()) {
3882 Some(rule) => rule,
3883 _ => continue,
3884 };
3885
3886 // For the rules with any important declaration, we insert them into
3887 // rule tree twice, one for normal level and another for important
3888 // level. So, we skip the important one to keep the specificity order of
3889 // rules.
3890 if node.importance().important() {
3891 continue;
3892 }
3893
3894 result.push(style_rule);
3895 }
3896
3897 rules.assign_from_iter_pod(result.into_iter().map(|src| {
3898 src.with_arc(|a| {
3899 a.with_raw_offset_arc(|arc| *Locked::<StyleRule>::arc_as_borrowed(arc) as *const _)
3900 })
3901 }))
3902 }
3903
3904 /// println_stderr!() calls Gecko's printf_stderr(), which, unlike eprintln!(),
3905 /// will funnel output to Android logcat.
3906 #[cfg(feature = "gecko_debug")]
3907 macro_rules! println_stderr {
3908 ($($e:expr),+) => {
3909 {
3910 let mut s = nsCString::new();
3911 write!(s, $($e),+).unwrap();
3912 s.write_char('\n').unwrap();
3913 unsafe { bindings::Gecko_PrintfStderr(&s); }
3914 }
3915 }
3916 }
3917
3918 #[cfg(feature = "gecko_debug")]
dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet)3919 fn dump_properties_and_rules(cv: &ComputedValues, properties: &LonghandIdSet) {
3920 println_stderr!(" Properties:");
3921 for p in properties.iter() {
3922 let mut v = String::new();
3923 cv.get_longhand_property_value(p, &mut CssWriter::new(&mut v))
3924 .unwrap();
3925 println_stderr!(" {:?}: {}", p, v);
3926 }
3927 println_stderr!(" Rules:");
3928 let global_style_data = &*GLOBAL_STYLE_DATA;
3929 let guard = global_style_data.shared_lock.read();
3930 for rn in cv.rules().self_and_ancestors() {
3931 if rn.importance().important() {
3932 continue;
3933 }
3934 if let Some(d) = rn.style_source().and_then(|s| s.as_declarations()) {
3935 println_stderr!(" [DeclarationBlock: {:?}]", d);
3936 }
3937 if let Some(r) = rn.style_source().and_then(|s| s.as_rule()) {
3938 let mut s = nsString::new();
3939 r.read_with(&guard).to_css(&guard, &mut s).unwrap();
3940 println_stderr!(" {}", s);
3941 }
3942 }
3943 }
3944
3945 #[cfg(feature = "gecko_debug")]
3946 #[no_mangle]
Servo_ComputedValues_EqualForCachedAnonymousContentStyle( a: &ComputedValues, b: &ComputedValues, ) -> bool3947 pub extern "C" fn Servo_ComputedValues_EqualForCachedAnonymousContentStyle(
3948 a: &ComputedValues,
3949 b: &ComputedValues,
3950 ) -> bool {
3951 let mut differing_properties = a.differing_properties(b);
3952
3953 // Ignore any difference in -x-lang, which we can't override in the
3954 // rules in minimal-xul.css, but which makes no difference for the
3955 // anonymous content subtrees we cache style for.
3956 differing_properties.remove(LonghandId::XLang);
3957
3958 // Ignore any difference in pref-controlled, inherited properties. These
3959 // properties may or may not be set by the 'all' declaration in the
3960 // minimal-xul.css rule, depending on whether the pref was enabled at the
3961 // time the UA sheets were parsed.
3962 //
3963 // If you add a new pref-controlled, inherited property, it must be defined
3964 // with `has_effect_on_gecko_scrollbars=False` to declare that
3965 // different values of this property on a <scrollbar> element or its
3966 // descendant scrollbar part elements should have no effect on their
3967 // rendering and behavior.
3968 //
3969 // If you do need a pref-controlled, inherited property to have an effect
3970 // on these elements, then you will need to add some checks to the
3971 // nsIAnonymousContentCreator::CreateAnonymousContent implementations of
3972 // ScrollFrameHelper and nsScrollbarFrame to clear the AnonymousContentKey
3973 // if a non-initial value is used.
3974 differing_properties.remove_all(&LonghandIdSet::has_no_effect_on_gecko_scrollbars());
3975
3976 if !differing_properties.is_empty() {
3977 println_stderr!("Actual style:");
3978 dump_properties_and_rules(a, &differing_properties);
3979 println_stderr!("Expected style:");
3980 dump_properties_and_rules(b, &differing_properties);
3981 }
3982
3983 differing_properties.is_empty()
3984 }
3985
3986 #[no_mangle]
Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet3987 pub extern "C" fn Servo_StyleSet_Init(doc: &structs::Document) -> *mut RawServoStyleSet {
3988 let data = Box::new(PerDocumentStyleData::new(doc));
3989
3990 // Do this here rather than in Servo_Initialize since we need a document to
3991 // get the default computed values from.
3992 style::gecko_properties::assert_initial_values_match(&data);
3993
3994 Box::into_raw(data) as *mut RawServoStyleSet
3995 }
3996
3997 #[no_mangle]
Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet)3998 pub extern "C" fn Servo_StyleSet_RebuildCachedData(raw_data: &RawServoStyleSet) {
3999 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
4000 data.stylist.device_mut().rebuild_cached_data();
4001 }
4002
4003 #[no_mangle]
Servo_StyleSet_Drop(data: *mut RawServoStyleSet)4004 pub unsafe extern "C" fn Servo_StyleSet_Drop(data: *mut RawServoStyleSet) {
4005 PerDocumentStyleData::drop_ffi(data);
4006 }
4007
4008 #[no_mangle]
Servo_StyleSet_CompatModeChanged(raw_data: &RawServoStyleSet)4009 pub unsafe extern "C" fn Servo_StyleSet_CompatModeChanged(raw_data: &RawServoStyleSet) {
4010 let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
4011 let quirks_mode = data.stylist.device().document().mCompatMode;
4012 data.stylist.set_quirks_mode(quirks_mode.into());
4013 }
4014
parse_property_into( declarations: &mut SourcePropertyDeclaration, property_id: PropertyId, value: &nsACString, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: QuirksMode, reporter: Option<&dyn ParseErrorReporter>, ) -> Result<(), ()>4015 fn parse_property_into(
4016 declarations: &mut SourcePropertyDeclaration,
4017 property_id: PropertyId,
4018 value: &nsACString,
4019 data: *mut URLExtraData,
4020 parsing_mode: structs::ParsingMode,
4021 quirks_mode: QuirksMode,
4022 reporter: Option<&dyn ParseErrorReporter>,
4023 ) -> Result<(), ()> {
4024 let value = unsafe { value.as_str_unchecked() };
4025 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
4026 let parsing_mode = ParsingMode::from_bits_truncate(parsing_mode);
4027
4028 parse_one_declaration_into(
4029 declarations,
4030 property_id,
4031 value,
4032 url_data,
4033 reporter,
4034 parsing_mode,
4035 quirks_mode,
4036 )
4037 }
4038
4039 #[no_mangle]
Servo_ParseProperty( property: nsCSSPropertyID, value: &nsACString, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: nsCompatibility, loader: *mut Loader, ) -> Strong<RawServoDeclarationBlock>4040 pub extern "C" fn Servo_ParseProperty(
4041 property: nsCSSPropertyID,
4042 value: &nsACString,
4043 data: *mut URLExtraData,
4044 parsing_mode: structs::ParsingMode,
4045 quirks_mode: nsCompatibility,
4046 loader: *mut Loader,
4047 ) -> Strong<RawServoDeclarationBlock> {
4048 let id = get_property_id_from_nscsspropertyid!(property, Strong::null());
4049 let mut declarations = SourcePropertyDeclaration::new();
4050 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4051 let result = parse_property_into(
4052 &mut declarations,
4053 id,
4054 value,
4055 data,
4056 parsing_mode,
4057 quirks_mode.into(),
4058 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4059 );
4060
4061 match result {
4062 Ok(()) => {
4063 let global_style_data = &*GLOBAL_STYLE_DATA;
4064 let mut block = PropertyDeclarationBlock::new();
4065 block.extend(declarations.drain(), Importance::Normal);
4066 Arc::new(global_style_data.shared_lock.wrap(block)).into_strong()
4067 },
4068 Err(_) => Strong::null(),
4069 }
4070 }
4071
4072 #[no_mangle]
Servo_ParseEasing( easing: &nsAString, data: *mut URLExtraData, output: &mut nsTimingFunction, ) -> bool4073 pub extern "C" fn Servo_ParseEasing(
4074 easing: &nsAString,
4075 data: *mut URLExtraData,
4076 output: &mut nsTimingFunction,
4077 ) -> bool {
4078 use style::properties::longhands::transition_timing_function;
4079
4080 // FIXME Dummy URL data would work fine here.
4081 let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
4082 let context = ParserContext::new(
4083 Origin::Author,
4084 url_data,
4085 Some(CssRuleType::Style),
4086 ParsingMode::DEFAULT,
4087 QuirksMode::NoQuirks,
4088 None,
4089 None,
4090 );
4091 let easing = easing.to_string();
4092 let mut input = ParserInput::new(&easing);
4093 let mut parser = Parser::new(&mut input);
4094 let result =
4095 parser.parse_entirely(|p| transition_timing_function::single_value::parse(&context, p));
4096 match result {
4097 Ok(parsed_easing) => {
4098 // We store as computed value in nsTimingFunction.
4099 (*output).mTiming = parsed_easing.to_computed_value_without_context();
4100 true
4101 },
4102 Err(_) => false,
4103 }
4104 }
4105
4106 #[no_mangle]
Servo_SerializeEasing(easing: &nsTimingFunction, output: &mut nsAString)4107 pub extern "C" fn Servo_SerializeEasing(easing: &nsTimingFunction, output: &mut nsAString) {
4108 easing.mTiming.to_css(&mut CssWriter::new(output)).unwrap();
4109 }
4110
4111 #[no_mangle]
Servo_GetProperties_Overriding_Animation( element: &RawGeckoElement, list: &nsTArray<nsCSSPropertyID>, set: &mut structs::nsCSSPropertyIDSet, )4112 pub extern "C" fn Servo_GetProperties_Overriding_Animation(
4113 element: &RawGeckoElement,
4114 list: &nsTArray<nsCSSPropertyID>,
4115 set: &mut structs::nsCSSPropertyIDSet,
4116 ) {
4117 let element = GeckoElement(element);
4118 let element_data = match element.borrow_data() {
4119 Some(data) => data,
4120 None => return,
4121 };
4122 let global_style_data = &*GLOBAL_STYLE_DATA;
4123 let guard = global_style_data.shared_lock.read();
4124 let guards = StylesheetGuards::same(&guard);
4125 let (overridden, custom) = element_data
4126 .styles
4127 .primary()
4128 .rules()
4129 .get_properties_overriding_animations(&guards);
4130 for p in list.iter() {
4131 match PropertyId::from_nscsspropertyid(*p) {
4132 Ok(property) => {
4133 if let PropertyId::Longhand(id) = property {
4134 if overridden.contains(id) {
4135 unsafe { Gecko_AddPropertyToSet(set, *p) };
4136 }
4137 }
4138 },
4139 Err(_) => {
4140 if *p == nsCSSPropertyID::eCSSPropertyExtra_variable && custom {
4141 unsafe { Gecko_AddPropertyToSet(set, *p) };
4142 }
4143 },
4144 }
4145 }
4146 }
4147
4148 #[no_mangle]
Servo_MatrixTransform_Operate( matrix_operator: MatrixTransformOperator, from: *const structs::Matrix4x4Components, to: *const structs::Matrix4x4Components, progress: f64, output: *mut structs::Matrix4x4Components, )4149 pub extern "C" fn Servo_MatrixTransform_Operate(
4150 matrix_operator: MatrixTransformOperator,
4151 from: *const structs::Matrix4x4Components,
4152 to: *const structs::Matrix4x4Components,
4153 progress: f64,
4154 output: *mut structs::Matrix4x4Components,
4155 ) {
4156 use self::MatrixTransformOperator::{Accumulate, Interpolate};
4157 use style::values::computed::transform::Matrix3D;
4158
4159 let from = Matrix3D::from(unsafe { from.as_ref() }.expect("not a valid 'from' matrix"));
4160 let to = Matrix3D::from(unsafe { to.as_ref() }.expect("not a valid 'to' matrix"));
4161 let result = match matrix_operator {
4162 Interpolate => from.animate(&to, Procedure::Interpolate { progress }),
4163 Accumulate => from.animate(
4164 &to,
4165 Procedure::Accumulate {
4166 count: progress as u64,
4167 },
4168 ),
4169 };
4170
4171 let output = unsafe { output.as_mut() }.expect("not a valid 'output' matrix");
4172 if let Ok(result) = result {
4173 *output = result.into();
4174 } else if progress < 0.5 {
4175 *output = from.clone().into();
4176 } else {
4177 *output = to.clone().into();
4178 }
4179 }
4180
4181 #[no_mangle]
Servo_ParseStyleAttribute( data: &nsACString, raw_extra_data: *mut URLExtraData, quirks_mode: nsCompatibility, loader: *mut Loader, ) -> Strong<RawServoDeclarationBlock>4182 pub unsafe extern "C" fn Servo_ParseStyleAttribute(
4183 data: &nsACString,
4184 raw_extra_data: *mut URLExtraData,
4185 quirks_mode: nsCompatibility,
4186 loader: *mut Loader,
4187 ) -> Strong<RawServoDeclarationBlock> {
4188 let global_style_data = &*GLOBAL_STYLE_DATA;
4189 let value = data.as_str_unchecked();
4190 let reporter = ErrorReporter::new(ptr::null_mut(), loader, raw_extra_data);
4191 let url_data = UrlExtraData::from_ptr_ref(&raw_extra_data);
4192 Arc::new(global_style_data.shared_lock.wrap(parse_style_attribute(
4193 value,
4194 url_data,
4195 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4196 quirks_mode.into(),
4197 )))
4198 .into_strong()
4199 }
4200
4201 #[no_mangle]
Servo_DeclarationBlock_CreateEmpty() -> Strong<RawServoDeclarationBlock>4202 pub extern "C" fn Servo_DeclarationBlock_CreateEmpty() -> Strong<RawServoDeclarationBlock> {
4203 let global_style_data = &*GLOBAL_STYLE_DATA;
4204 Arc::new(
4205 global_style_data
4206 .shared_lock
4207 .wrap(PropertyDeclarationBlock::new()),
4208 )
4209 .into_strong()
4210 }
4211
4212 #[no_mangle]
Servo_DeclarationBlock_Clone( declarations: &RawServoDeclarationBlock, ) -> Strong<RawServoDeclarationBlock>4213 pub extern "C" fn Servo_DeclarationBlock_Clone(
4214 declarations: &RawServoDeclarationBlock,
4215 ) -> Strong<RawServoDeclarationBlock> {
4216 let global_style_data = &*GLOBAL_STYLE_DATA;
4217 let guard = global_style_data.shared_lock.read();
4218 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
4219 Arc::new(
4220 global_style_data
4221 .shared_lock
4222 .wrap(declarations.read_with(&guard).clone()),
4223 )
4224 .into_strong()
4225 }
4226
4227 #[no_mangle]
Servo_DeclarationBlock_Equals( a: &RawServoDeclarationBlock, b: &RawServoDeclarationBlock, ) -> bool4228 pub extern "C" fn Servo_DeclarationBlock_Equals(
4229 a: &RawServoDeclarationBlock,
4230 b: &RawServoDeclarationBlock,
4231 ) -> bool {
4232 let global_style_data = &*GLOBAL_STYLE_DATA;
4233 let guard = global_style_data.shared_lock.read();
4234 *Locked::<PropertyDeclarationBlock>::as_arc(&a)
4235 .read_with(&guard)
4236 .declarations() ==
4237 *Locked::<PropertyDeclarationBlock>::as_arc(&b)
4238 .read_with(&guard)
4239 .declarations()
4240 }
4241
4242 #[no_mangle]
Servo_DeclarationBlock_GetCssText( declarations: &RawServoDeclarationBlock, result: &mut nsAString, )4243 pub extern "C" fn Servo_DeclarationBlock_GetCssText(
4244 declarations: &RawServoDeclarationBlock,
4245 result: &mut nsAString,
4246 ) {
4247 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4248 decls.to_css(result).unwrap()
4249 })
4250 }
4251
4252 #[no_mangle]
Servo_DeclarationBlock_SerializeOneValue( declarations: &RawServoDeclarationBlock, property_id: nsCSSPropertyID, buffer: &mut nsAString, computed_values: Option<&ComputedValues>, custom_properties: Option<&RawServoDeclarationBlock>, raw_data: &RawServoStyleSet, )4253 pub extern "C" fn Servo_DeclarationBlock_SerializeOneValue(
4254 declarations: &RawServoDeclarationBlock,
4255 property_id: nsCSSPropertyID,
4256 buffer: &mut nsAString,
4257 computed_values: Option<&ComputedValues>,
4258 custom_properties: Option<&RawServoDeclarationBlock>,
4259 raw_data: &RawServoStyleSet,
4260 ) {
4261 let property_id = get_property_id_from_nscsspropertyid!(property_id, ());
4262
4263 let global_style_data = &*GLOBAL_STYLE_DATA;
4264 let guard = global_style_data.shared_lock.read();
4265 let decls = Locked::<PropertyDeclarationBlock>::as_arc(&declarations).read_with(&guard);
4266
4267 let custom_properties =
4268 Locked::<PropertyDeclarationBlock>::arc_from_borrowed(&custom_properties);
4269 let custom_properties = custom_properties.map(|block| block.read_with(&guard));
4270 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
4271 let rv = decls.single_value_to_css(&property_id, buffer, computed_values, custom_properties, &data.stylist.device());
4272 debug_assert!(rv.is_ok());
4273 }
4274
4275 #[no_mangle]
Servo_SerializeFontValueForCanvas( declarations: &RawServoDeclarationBlock, buffer: &mut nsAString, )4276 pub unsafe extern "C" fn Servo_SerializeFontValueForCanvas(
4277 declarations: &RawServoDeclarationBlock,
4278 buffer: &mut nsAString,
4279 ) {
4280 use style::properties::shorthands::font;
4281 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4282 let longhands = match font::LonghandsToSerialize::from_iter(decls.declarations().iter()) {
4283 Ok(l) => l,
4284 Err(()) => {
4285 warn!("Unexpected property!");
4286 return;
4287 },
4288 };
4289
4290 let rv = longhands.to_css(&mut CssWriter::new(buffer));
4291 debug_assert!(rv.is_ok());
4292 })
4293 }
4294
4295 #[no_mangle]
Servo_DeclarationBlock_Count(declarations: &RawServoDeclarationBlock) -> u324296 pub extern "C" fn Servo_DeclarationBlock_Count(declarations: &RawServoDeclarationBlock) -> u32 {
4297 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4298 decls.declarations().len() as u32
4299 })
4300 }
4301
4302 #[no_mangle]
Servo_DeclarationBlock_GetNthProperty( declarations: &RawServoDeclarationBlock, index: u32, result: &mut nsACString, ) -> bool4303 pub extern "C" fn Servo_DeclarationBlock_GetNthProperty(
4304 declarations: &RawServoDeclarationBlock,
4305 index: u32,
4306 result: &mut nsACString,
4307 ) -> bool {
4308 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4309 if let Some(decl) = decls.declarations().get(index as usize) {
4310 result.assign(&decl.id().name());
4311 true
4312 } else {
4313 false
4314 }
4315 })
4316 }
4317
4318 macro_rules! get_property_id_from_property {
4319 ($property: ident, $ret: expr) => {{
4320 let property = $property.as_str_unchecked();
4321 match PropertyId::parse_enabled_for_all_content(property) {
4322 Ok(property_id) => property_id,
4323 Err(_) => return $ret,
4324 }
4325 }};
4326 }
4327
get_property_value( declarations: &RawServoDeclarationBlock, property_id: PropertyId, value: &mut nsAString, )4328 unsafe fn get_property_value(
4329 declarations: &RawServoDeclarationBlock,
4330 property_id: PropertyId,
4331 value: &mut nsAString,
4332 ) {
4333 // This callsite is hot enough that the lock acquisition shows up in profiles.
4334 // Using an unchecked read here improves our performance by ~10% on the
4335 // microbenchmark in bug 1355599.
4336 read_locked_arc_unchecked(declarations, |decls: &PropertyDeclarationBlock| {
4337 decls.property_value_to_css(&property_id, value).unwrap();
4338 })
4339 }
4340
4341 #[no_mangle]
Servo_DeclarationBlock_GetPropertyValue( declarations: &RawServoDeclarationBlock, property: &nsACString, value: &mut nsAString, )4342 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValue(
4343 declarations: &RawServoDeclarationBlock,
4344 property: &nsACString,
4345 value: &mut nsAString,
4346 ) {
4347 get_property_value(
4348 declarations,
4349 get_property_id_from_property!(property, ()),
4350 value,
4351 )
4352 }
4353
4354 #[no_mangle]
Servo_DeclarationBlock_GetPropertyValueById( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: &mut nsAString, )4355 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyValueById(
4356 declarations: &RawServoDeclarationBlock,
4357 property: nsCSSPropertyID,
4358 value: &mut nsAString,
4359 ) {
4360 get_property_value(
4361 declarations,
4362 get_property_id_from_nscsspropertyid!(property, ()),
4363 value,
4364 )
4365 }
4366
4367 #[no_mangle]
Servo_DeclarationBlock_GetPropertyIsImportant( declarations: &RawServoDeclarationBlock, property: &nsACString, ) -> bool4368 pub unsafe extern "C" fn Servo_DeclarationBlock_GetPropertyIsImportant(
4369 declarations: &RawServoDeclarationBlock,
4370 property: &nsACString,
4371 ) -> bool {
4372 let property_id = get_property_id_from_property!(property, false);
4373 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4374 decls.property_priority(&property_id).important()
4375 })
4376 }
4377
4378 #[inline(always)]
set_property_to_declarations( block: &RawServoDeclarationBlock, parsed_declarations: &mut SourcePropertyDeclaration, before_change_closure: DeclarationBlockMutationClosure, importance: Importance, ) -> bool4379 fn set_property_to_declarations(
4380 block: &RawServoDeclarationBlock,
4381 parsed_declarations: &mut SourcePropertyDeclaration,
4382 before_change_closure: DeclarationBlockMutationClosure,
4383 importance: Importance,
4384 ) -> bool {
4385 let mut updates = Default::default();
4386 let will_change = read_locked_arc(block, |decls: &PropertyDeclarationBlock| {
4387 decls.prepare_for_update(&parsed_declarations, importance, &mut updates)
4388 });
4389 if !will_change {
4390 return false;
4391 }
4392
4393 before_change_closure.invoke();
4394 write_locked_arc(block, |decls: &mut PropertyDeclarationBlock| {
4395 decls.update(parsed_declarations.drain(), importance, &mut updates)
4396 });
4397 true
4398 }
4399
set_property( declarations: &RawServoDeclarationBlock, property_id: PropertyId, value: &nsACString, is_important: bool, data: *mut URLExtraData, parsing_mode: structs::ParsingMode, quirks_mode: QuirksMode, loader: *mut Loader, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4400 fn set_property(
4401 declarations: &RawServoDeclarationBlock,
4402 property_id: PropertyId,
4403 value: &nsACString,
4404 is_important: bool,
4405 data: *mut URLExtraData,
4406 parsing_mode: structs::ParsingMode,
4407 quirks_mode: QuirksMode,
4408 loader: *mut Loader,
4409 before_change_closure: DeclarationBlockMutationClosure,
4410 ) -> bool {
4411 let mut source_declarations = SourcePropertyDeclaration::new();
4412 let reporter = ErrorReporter::new(ptr::null_mut(), loader, data);
4413 let result = parse_property_into(
4414 &mut source_declarations,
4415 property_id,
4416 value,
4417 data,
4418 parsing_mode,
4419 quirks_mode,
4420 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
4421 );
4422
4423 if result.is_err() {
4424 return false;
4425 }
4426
4427 let importance = if is_important {
4428 Importance::Important
4429 } else {
4430 Importance::Normal
4431 };
4432
4433 set_property_to_declarations(
4434 declarations,
4435 &mut source_declarations,
4436 before_change_closure,
4437 importance,
4438 )
4439 }
4440
4441 #[no_mangle]
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, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4442 pub unsafe extern "C" fn Servo_DeclarationBlock_SetProperty(
4443 declarations: &RawServoDeclarationBlock,
4444 property: &nsACString,
4445 value: &nsACString,
4446 is_important: bool,
4447 data: *mut URLExtraData,
4448 parsing_mode: structs::ParsingMode,
4449 quirks_mode: nsCompatibility,
4450 loader: *mut Loader,
4451 before_change_closure: DeclarationBlockMutationClosure,
4452 ) -> bool {
4453 set_property(
4454 declarations,
4455 get_property_id_from_property!(property, false),
4456 value,
4457 is_important,
4458 data,
4459 parsing_mode,
4460 quirks_mode.into(),
4461 loader,
4462 before_change_closure,
4463 )
4464 }
4465
4466 #[no_mangle]
Servo_DeclarationBlock_SetPropertyToAnimationValue( declarations: &RawServoDeclarationBlock, animation_value: &RawServoAnimationValue, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4467 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyToAnimationValue(
4468 declarations: &RawServoDeclarationBlock,
4469 animation_value: &RawServoAnimationValue,
4470 before_change_closure: DeclarationBlockMutationClosure,
4471 ) -> bool {
4472 let mut source_declarations =
4473 SourcePropertyDeclaration::with_one(AnimationValue::as_arc(&animation_value).uncompute());
4474
4475 set_property_to_declarations(
4476 declarations,
4477 &mut source_declarations,
4478 before_change_closure,
4479 Importance::Normal,
4480 )
4481 }
4482
4483 #[no_mangle]
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, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4484 pub unsafe extern "C" fn Servo_DeclarationBlock_SetPropertyById(
4485 declarations: &RawServoDeclarationBlock,
4486 property: nsCSSPropertyID,
4487 value: &nsACString,
4488 is_important: bool,
4489 data: *mut URLExtraData,
4490 parsing_mode: structs::ParsingMode,
4491 quirks_mode: nsCompatibility,
4492 loader: *mut Loader,
4493 before_change_closure: DeclarationBlockMutationClosure,
4494 ) -> bool {
4495 set_property(
4496 declarations,
4497 get_property_id_from_nscsspropertyid!(property, false),
4498 value,
4499 is_important,
4500 data,
4501 parsing_mode,
4502 quirks_mode.into(),
4503 loader,
4504 before_change_closure,
4505 )
4506 }
4507
remove_property( declarations: &RawServoDeclarationBlock, property_id: PropertyId, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4508 fn remove_property(
4509 declarations: &RawServoDeclarationBlock,
4510 property_id: PropertyId,
4511 before_change_closure: DeclarationBlockMutationClosure,
4512 ) -> bool {
4513 let first_declaration = read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4514 decls.first_declaration_to_remove(&property_id)
4515 });
4516
4517 let first_declaration = match first_declaration {
4518 Some(i) => i,
4519 None => return false,
4520 };
4521
4522 before_change_closure.invoke();
4523 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4524 decls.remove_property(&property_id, first_declaration)
4525 });
4526
4527 true
4528 }
4529
4530 #[no_mangle]
Servo_DeclarationBlock_RemoveProperty( declarations: &RawServoDeclarationBlock, property: &nsACString, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4531 pub unsafe extern "C" fn Servo_DeclarationBlock_RemoveProperty(
4532 declarations: &RawServoDeclarationBlock,
4533 property: &nsACString,
4534 before_change_closure: DeclarationBlockMutationClosure,
4535 ) -> bool {
4536 remove_property(
4537 declarations,
4538 get_property_id_from_property!(property, false),
4539 before_change_closure,
4540 )
4541 }
4542
4543 #[no_mangle]
Servo_DeclarationBlock_RemovePropertyById( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, before_change_closure: DeclarationBlockMutationClosure, ) -> bool4544 pub extern "C" fn Servo_DeclarationBlock_RemovePropertyById(
4545 declarations: &RawServoDeclarationBlock,
4546 property: nsCSSPropertyID,
4547 before_change_closure: DeclarationBlockMutationClosure,
4548 ) -> bool {
4549 remove_property(
4550 declarations,
4551 get_property_id_from_nscsspropertyid!(property, false),
4552 before_change_closure,
4553 )
4554 }
4555
4556 #[no_mangle]
Servo_MediaList_Create() -> Strong<RawServoMediaList>4557 pub extern "C" fn Servo_MediaList_Create() -> Strong<RawServoMediaList> {
4558 let global_style_data = &*GLOBAL_STYLE_DATA;
4559 Arc::new(global_style_data.shared_lock.wrap(MediaList::empty())).into_strong()
4560 }
4561
4562 #[no_mangle]
Servo_MediaList_DeepClone(list: &RawServoMediaList) -> Strong<RawServoMediaList>4563 pub extern "C" fn Servo_MediaList_DeepClone(list: &RawServoMediaList) -> Strong<RawServoMediaList> {
4564 let global_style_data = &*GLOBAL_STYLE_DATA;
4565 read_locked_arc(list, |list: &MediaList| {
4566 Arc::new(global_style_data.shared_lock.wrap(list.clone())).into_strong()
4567 })
4568 }
4569
4570 #[no_mangle]
Servo_MediaList_Matches( list: &RawServoMediaList, raw_data: &RawServoStyleSet, ) -> bool4571 pub extern "C" fn Servo_MediaList_Matches(
4572 list: &RawServoMediaList,
4573 raw_data: &RawServoStyleSet,
4574 ) -> bool {
4575 let per_doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
4576 read_locked_arc(list, |list: &MediaList| {
4577 list.evaluate(
4578 per_doc_data.stylist.device(),
4579 per_doc_data.stylist.quirks_mode(),
4580 )
4581 })
4582 }
4583
4584 #[no_mangle]
Servo_DeclarationBlock_HasCSSWideKeyword( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, ) -> bool4585 pub extern "C" fn Servo_DeclarationBlock_HasCSSWideKeyword(
4586 declarations: &RawServoDeclarationBlock,
4587 property: nsCSSPropertyID,
4588 ) -> bool {
4589 let property_id = get_property_id_from_nscsspropertyid!(property, false);
4590 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4591 decls.has_css_wide_keyword(&property_id)
4592 })
4593 }
4594
4595 #[no_mangle]
Servo_MediaList_GetText(list: &RawServoMediaList, result: &mut nsAString)4596 pub extern "C" fn Servo_MediaList_GetText(list: &RawServoMediaList, result: &mut nsAString) {
4597 read_locked_arc(list, |list: &MediaList| {
4598 list.to_css(&mut CssWriter::new(result)).unwrap();
4599 })
4600 }
4601
4602 #[no_mangle]
Servo_MediaList_SetText( list: &RawServoMediaList, text: &nsACString, caller_type: CallerType, )4603 pub unsafe extern "C" fn Servo_MediaList_SetText(
4604 list: &RawServoMediaList,
4605 text: &nsACString,
4606 caller_type: CallerType,
4607 ) {
4608 let text = text.as_str_unchecked();
4609
4610 let mut input = ParserInput::new(&text);
4611 let mut parser = Parser::new(&mut input);
4612 let url_data = dummy_url_data();
4613
4614 // TODO(emilio): If the need for `CallerType` appears in more places,
4615 // consider adding an explicit member in `ParserContext` instead of doing
4616 // this (or adding a dummy "chrome://" url data).
4617 //
4618 // For media query parsing it's effectively the same, so for now...
4619 let origin = match caller_type {
4620 CallerType::System => Origin::UserAgent,
4621 CallerType::NonSystem => Origin::Author,
4622 };
4623
4624 let context = ParserContext::new(
4625 origin,
4626 url_data,
4627 Some(CssRuleType::Media),
4628 ParsingMode::DEFAULT,
4629 QuirksMode::NoQuirks,
4630 // TODO(emilio): Looks like error reporting could be useful here?
4631 None,
4632 None,
4633 );
4634
4635 write_locked_arc(list, |list: &mut MediaList| {
4636 *list = MediaList::parse(&context, &mut parser);
4637 })
4638 }
4639
4640 #[no_mangle]
Servo_MediaList_GetLength(list: &RawServoMediaList) -> u324641 pub extern "C" fn Servo_MediaList_GetLength(list: &RawServoMediaList) -> u32 {
4642 read_locked_arc(list, |list: &MediaList| list.media_queries.len() as u32)
4643 }
4644
4645 #[no_mangle]
Servo_MediaList_GetMediumAt( list: &RawServoMediaList, index: u32, result: &mut nsAString, ) -> bool4646 pub extern "C" fn Servo_MediaList_GetMediumAt(
4647 list: &RawServoMediaList,
4648 index: u32,
4649 result: &mut nsAString,
4650 ) -> bool {
4651 read_locked_arc(list, |list: &MediaList| {
4652 let media_query = match list.media_queries.get(index as usize) {
4653 Some(mq) => mq,
4654 None => return false,
4655 };
4656 media_query.to_css(&mut CssWriter::new(result)).unwrap();
4657 true
4658 })
4659 }
4660
4661 #[no_mangle]
Servo_MediaList_AppendMedium( list: &RawServoMediaList, new_medium: &nsACString, )4662 pub extern "C" fn Servo_MediaList_AppendMedium(
4663 list: &RawServoMediaList,
4664 new_medium: &nsACString,
4665 ) {
4666 let new_medium = unsafe { new_medium.as_str_unchecked() };
4667 let url_data = unsafe { dummy_url_data() };
4668 let context = ParserContext::new_for_cssom(
4669 url_data,
4670 Some(CssRuleType::Media),
4671 ParsingMode::DEFAULT,
4672 QuirksMode::NoQuirks,
4673 None,
4674 None,
4675 );
4676 write_locked_arc(list, |list: &mut MediaList| {
4677 list.append_medium(&context, new_medium);
4678 })
4679 }
4680
4681 #[no_mangle]
Servo_MediaList_DeleteMedium( list: &RawServoMediaList, old_medium: &nsACString, ) -> bool4682 pub extern "C" fn Servo_MediaList_DeleteMedium(
4683 list: &RawServoMediaList,
4684 old_medium: &nsACString,
4685 ) -> bool {
4686 let old_medium = unsafe { old_medium.as_str_unchecked() };
4687 let url_data = unsafe { dummy_url_data() };
4688 let context = ParserContext::new_for_cssom(
4689 url_data,
4690 Some(CssRuleType::Media),
4691 ParsingMode::DEFAULT,
4692 QuirksMode::NoQuirks,
4693 None,
4694 None,
4695 );
4696 write_locked_arc(list, |list: &mut MediaList| {
4697 list.delete_medium(&context, old_medium)
4698 })
4699 }
4700
4701 #[no_mangle]
Servo_MediaList_SizeOfIncludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, list: &RawServoMediaList, ) -> usize4702 pub extern "C" fn Servo_MediaList_SizeOfIncludingThis(
4703 malloc_size_of: GeckoMallocSizeOf,
4704 malloc_enclosing_size_of: GeckoMallocSizeOf,
4705 list: &RawServoMediaList,
4706 ) -> usize {
4707 use malloc_size_of::MallocSizeOf;
4708 use malloc_size_of::MallocUnconditionalShallowSizeOf;
4709
4710 let global_style_data = &*GLOBAL_STYLE_DATA;
4711 let guard = global_style_data.shared_lock.read();
4712
4713 let mut ops = MallocSizeOfOps::new(
4714 malloc_size_of.unwrap(),
4715 Some(malloc_enclosing_size_of.unwrap()),
4716 None,
4717 );
4718
4719 Locked::<MediaList>::as_arc(&list).with_arc(|list| {
4720 let mut n = 0;
4721 n += list.unconditional_shallow_size_of(&mut ops);
4722 n += list.read_with(&guard).size_of(&mut ops);
4723 n
4724 })
4725 }
4726
4727 macro_rules! get_longhand_from_id {
4728 ($id:expr) => {
4729 match PropertyId::from_nscsspropertyid($id) {
4730 Ok(PropertyId::Longhand(long)) => long,
4731 _ => {
4732 panic!("stylo: unknown presentation property with id");
4733 },
4734 }
4735 };
4736 }
4737
4738 macro_rules! match_wrap_declared {
4739 ($longhand:ident, $($property:ident => $inner:expr,)*) => (
4740 match $longhand {
4741 $(
4742 LonghandId::$property => PropertyDeclaration::$property($inner),
4743 )*
4744 _ => {
4745 panic!("stylo: Don't know how to handle presentation property");
4746 }
4747 }
4748 )
4749 }
4750
4751 #[no_mangle]
Servo_DeclarationBlock_PropertyIsSet( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, ) -> bool4752 pub extern "C" fn Servo_DeclarationBlock_PropertyIsSet(
4753 declarations: &RawServoDeclarationBlock,
4754 property: nsCSSPropertyID,
4755 ) -> bool {
4756 read_locked_arc(declarations, |decls: &PropertyDeclarationBlock| {
4757 decls.contains(get_longhand_from_id!(property))
4758 })
4759 }
4760
4761 #[no_mangle]
Servo_DeclarationBlock_SetIdentStringValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: *mut nsAtom, )4762 pub unsafe extern "C" fn Servo_DeclarationBlock_SetIdentStringValue(
4763 declarations: &RawServoDeclarationBlock,
4764 property: nsCSSPropertyID,
4765 value: *mut nsAtom,
4766 ) {
4767 use style::properties::longhands::_x_lang::computed_value::T as Lang;
4768 use style::properties::PropertyDeclaration;
4769
4770 let long = get_longhand_from_id!(property);
4771 let prop = match_wrap_declared! { long,
4772 XLang => Lang(Atom::from_raw(value)),
4773 };
4774 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4775 decls.push(prop, Importance::Normal);
4776 })
4777 }
4778
4779 #[no_mangle]
4780 #[allow(unreachable_code)]
Servo_DeclarationBlock_SetKeywordValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: i32, )4781 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
4782 declarations: &RawServoDeclarationBlock,
4783 property: nsCSSPropertyID,
4784 value: i32,
4785 ) {
4786 use num_traits::FromPrimitive;
4787 use style::properties::longhands;
4788 use style::properties::PropertyDeclaration;
4789 use style::values::generics::box_::{VerticalAlign, VerticalAlignKeyword};
4790 use style::values::generics::font::FontStyle;
4791 use style::values::specified::{BorderStyle, Clear, Display, Float, TextAlign};
4792
4793 fn get_from_computed<T>(value: u32) -> T
4794 where
4795 T: ToComputedValue,
4796 T::ComputedValue: FromPrimitive,
4797 {
4798 T::from_computed_value(&T::ComputedValue::from_u32(value).unwrap())
4799 }
4800
4801 let long = get_longhand_from_id!(property);
4802 let value = value as u32;
4803
4804 let prop = match_wrap_declared! { long,
4805 MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
4806 Direction => get_from_computed::<longhands::direction::SpecifiedValue>(value),
4807 Display => get_from_computed::<Display>(value),
4808 Float => get_from_computed::<Float>(value),
4809 Clear => get_from_computed::<Clear>(value),
4810 VerticalAlign => VerticalAlign::Keyword(VerticalAlignKeyword::from_u32(value).unwrap()),
4811 TextAlign => get_from_computed::<TextAlign>(value),
4812 TextEmphasisPosition => longhands::text_emphasis_position::SpecifiedValue::from_gecko_keyword(value),
4813 FontSize => {
4814 // We rely on Gecko passing in font-size values (0...7) here.
4815 longhands::font_size::SpecifiedValue::from_html_size(value as u8)
4816 },
4817 FontStyle => {
4818 let val = if value == structs::NS_FONT_STYLE_ITALIC {
4819 FontStyle::Italic
4820 } else {
4821 debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
4822 FontStyle::Normal
4823 };
4824
4825 ToComputedValue::from_computed_value(&val)
4826 },
4827 FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
4828 ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
4829 MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
4830 WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
4831 CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value),
4832 BorderTopStyle => get_from_computed::<BorderStyle>(value),
4833 BorderRightStyle => get_from_computed::<BorderStyle>(value),
4834 BorderBottomStyle => get_from_computed::<BorderStyle>(value),
4835 BorderLeftStyle => get_from_computed::<BorderStyle>(value),
4836 };
4837 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4838 decls.push(prop, Importance::Normal);
4839 })
4840 }
4841
4842 #[no_mangle]
Servo_DeclarationBlock_SetIntValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: i32, )4843 pub extern "C" fn Servo_DeclarationBlock_SetIntValue(
4844 declarations: &RawServoDeclarationBlock,
4845 property: nsCSSPropertyID,
4846 value: i32,
4847 ) {
4848 use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
4849 use style::properties::PropertyDeclaration;
4850 use style::values::specified::Integer;
4851
4852 let long = get_longhand_from_id!(property);
4853 let prop = match_wrap_declared! { long,
4854 XSpan => Integer::new(value),
4855 // Gecko uses Integer values to signal that it is relative
4856 MozScriptLevel => MozScriptLevel::Relative(value),
4857 };
4858 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4859 decls.push(prop, Importance::Normal);
4860 })
4861 }
4862
4863 #[no_mangle]
Servo_DeclarationBlock_SetCounterResetListItem( declarations: &RawServoDeclarationBlock, counter_value: i32, )4864 pub extern "C" fn Servo_DeclarationBlock_SetCounterResetListItem(
4865 declarations: &RawServoDeclarationBlock,
4866 counter_value: i32,
4867 ) {
4868 use style::properties::PropertyDeclaration;
4869 use style::values::generics::counters::{CounterPair, CounterSetOrReset};
4870
4871 let prop = PropertyDeclaration::CounterReset(CounterSetOrReset::new(vec![CounterPair {
4872 name: CustomIdent(atom!("list-item")),
4873 value: style::values::specified::Integer::new(counter_value),
4874 }]));
4875 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4876 decls.push(prop, Importance::Normal);
4877 })
4878 }
4879
4880 #[no_mangle]
Servo_DeclarationBlock_SetCounterSetListItem( declarations: &RawServoDeclarationBlock, counter_value: i32, )4881 pub extern "C" fn Servo_DeclarationBlock_SetCounterSetListItem(
4882 declarations: &RawServoDeclarationBlock,
4883 counter_value: i32,
4884 ) {
4885 use style::properties::PropertyDeclaration;
4886 use style::values::generics::counters::{CounterPair, CounterSetOrReset};
4887
4888 let prop = PropertyDeclaration::CounterSet(CounterSetOrReset::new(vec![CounterPair {
4889 name: CustomIdent(atom!("list-item")),
4890 value: style::values::specified::Integer::new(counter_value),
4891 }]));
4892 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4893 decls.push(prop, Importance::Normal);
4894 })
4895 }
4896
4897 #[no_mangle]
Servo_DeclarationBlock_SetPixelValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )4898 pub extern "C" fn Servo_DeclarationBlock_SetPixelValue(
4899 declarations: &RawServoDeclarationBlock,
4900 property: nsCSSPropertyID,
4901 value: f32,
4902 ) {
4903 use style::properties::longhands::border_spacing::SpecifiedValue as BorderSpacing;
4904 use style::properties::PropertyDeclaration;
4905 use style::values::generics::length::LengthPercentageOrAuto;
4906 use style::values::generics::length::Size;
4907 use style::values::generics::NonNegative;
4908 use style::values::specified::length::LengthPercentage;
4909 use style::values::specified::length::NonNegativeLengthPercentage;
4910 use style::values::specified::length::{NoCalcLength, NonNegativeLength};
4911 use style::values::specified::{BorderCornerRadius, BorderSideWidth};
4912
4913 let long = get_longhand_from_id!(property);
4914 let nocalc = NoCalcLength::from_px(value);
4915 let lp = LengthPercentage::Length(nocalc);
4916 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
4917 let prop = match_wrap_declared! { long,
4918 Height => Size::LengthPercentage(NonNegative(lp)),
4919 Width => Size::LengthPercentage(NonNegative(lp)),
4920 BorderTopWidth => BorderSideWidth::Length(nocalc.into()),
4921 BorderRightWidth => BorderSideWidth::Length(nocalc.into()),
4922 BorderBottomWidth => BorderSideWidth::Length(nocalc.into()),
4923 BorderLeftWidth => BorderSideWidth::Length(nocalc.into()),
4924 MarginTop => lp_or_auto,
4925 MarginRight => lp_or_auto,
4926 MarginBottom => lp_or_auto,
4927 MarginLeft => lp_or_auto,
4928 PaddingTop => NonNegative(lp),
4929 PaddingRight => NonNegative(lp),
4930 PaddingBottom => NonNegative(lp),
4931 PaddingLeft => NonNegative(lp),
4932 BorderSpacing => {
4933 let v = NonNegativeLength::from(nocalc);
4934 Box::new(BorderSpacing::new(v.clone(), v))
4935 },
4936 BorderTopLeftRadius => {
4937 let length = NonNegativeLengthPercentage::from(nocalc);
4938 Box::new(BorderCornerRadius::new(length.clone(), length))
4939 },
4940 BorderTopRightRadius => {
4941 let length = NonNegativeLengthPercentage::from(nocalc);
4942 Box::new(BorderCornerRadius::new(length.clone(), length))
4943 },
4944 BorderBottomLeftRadius => {
4945 let length = NonNegativeLengthPercentage::from(nocalc);
4946 Box::new(BorderCornerRadius::new(length.clone(), length))
4947 },
4948 BorderBottomRightRadius => {
4949 let length = NonNegativeLengthPercentage::from(nocalc);
4950 Box::new(BorderCornerRadius::new(length.clone(), length))
4951 },
4952 };
4953 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
4954 decls.push(prop, Importance::Normal);
4955 })
4956 }
4957
4958 #[no_mangle]
Servo_DeclarationBlock_SetLengthValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, unit: structs::nsCSSUnit, )4959 pub extern "C" fn Servo_DeclarationBlock_SetLengthValue(
4960 declarations: &RawServoDeclarationBlock,
4961 property: nsCSSPropertyID,
4962 value: f32,
4963 unit: structs::nsCSSUnit,
4964 ) {
4965 use style::properties::longhands::_moz_script_min_size::SpecifiedValue as MozScriptMinSize;
4966 use style::properties::PropertyDeclaration;
4967 use style::values::generics::length::{LengthPercentageOrAuto, Size};
4968 use style::values::generics::NonNegative;
4969 use style::values::specified::length::{LengthPercentage, NoCalcLength};
4970 use style::values::specified::length::{AbsoluteLength, FontRelativeLength};
4971 use style::values::specified::FontSize;
4972
4973 let long = get_longhand_from_id!(property);
4974 let nocalc = match unit {
4975 structs::nsCSSUnit::eCSSUnit_EM => {
4976 NoCalcLength::FontRelative(FontRelativeLength::Em(value))
4977 },
4978 structs::nsCSSUnit::eCSSUnit_XHeight => {
4979 NoCalcLength::FontRelative(FontRelativeLength::Ex(value))
4980 },
4981 structs::nsCSSUnit::eCSSUnit_Pixel => NoCalcLength::Absolute(AbsoluteLength::Px(value)),
4982 structs::nsCSSUnit::eCSSUnit_Inch => NoCalcLength::Absolute(AbsoluteLength::In(value)),
4983 structs::nsCSSUnit::eCSSUnit_Centimeter => {
4984 NoCalcLength::Absolute(AbsoluteLength::Cm(value))
4985 },
4986 structs::nsCSSUnit::eCSSUnit_Millimeter => {
4987 NoCalcLength::Absolute(AbsoluteLength::Mm(value))
4988 },
4989 structs::nsCSSUnit::eCSSUnit_Point => NoCalcLength::Absolute(AbsoluteLength::Pt(value)),
4990 structs::nsCSSUnit::eCSSUnit_Pica => NoCalcLength::Absolute(AbsoluteLength::Pc(value)),
4991 structs::nsCSSUnit::eCSSUnit_Quarter => NoCalcLength::Absolute(AbsoluteLength::Q(value)),
4992 _ => unreachable!("Unknown unit passed to SetLengthValue"),
4993 };
4994
4995 let prop = match_wrap_declared! { long,
4996 Width => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
4997 Height => Size::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
4998 X => LengthPercentage::Length(nocalc),
4999 Y => LengthPercentage::Length(nocalc),
5000 Cx => LengthPercentage::Length(nocalc),
5001 Cy => LengthPercentage::Length(nocalc),
5002 R => NonNegative(LengthPercentage::Length(nocalc)),
5003 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5004 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(LengthPercentage::Length(nocalc))),
5005 FontSize => FontSize::Length(LengthPercentage::Length(nocalc)),
5006 MozScriptMinSize => MozScriptMinSize(nocalc),
5007 };
5008 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5009 decls.push(prop, Importance::Normal);
5010 })
5011 }
5012
5013 #[no_mangle]
Servo_DeclarationBlock_SetNumberValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )5014 pub extern "C" fn Servo_DeclarationBlock_SetNumberValue(
5015 declarations: &RawServoDeclarationBlock,
5016 property: nsCSSPropertyID,
5017 value: f32,
5018 ) {
5019 use style::properties::longhands::_moz_script_level::SpecifiedValue as MozScriptLevel;
5020 use style::properties::longhands::_moz_script_size_multiplier::SpecifiedValue as MozScriptSizeMultiplier;
5021 use style::properties::PropertyDeclaration;
5022
5023 let long = get_longhand_from_id!(property);
5024
5025 let prop = match_wrap_declared! { long,
5026 MozScriptSizeMultiplier => MozScriptSizeMultiplier(value),
5027 // Gecko uses Number values to signal that it is absolute
5028 MozScriptLevel => MozScriptLevel::MozAbsolute(value as i32),
5029 };
5030 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5031 decls.push(prop, Importance::Normal);
5032 })
5033 }
5034
5035 #[no_mangle]
Servo_DeclarationBlock_SetPercentValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: f32, )5036 pub extern "C" fn Servo_DeclarationBlock_SetPercentValue(
5037 declarations: &RawServoDeclarationBlock,
5038 property: nsCSSPropertyID,
5039 value: f32,
5040 ) {
5041 use style::properties::PropertyDeclaration;
5042 use style::values::computed::Percentage;
5043 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5044 use style::values::generics::NonNegative;
5045 use style::values::specified::length::LengthPercentage;
5046 use style::values::specified::FontSize;
5047
5048 let long = get_longhand_from_id!(property);
5049 let pc = Percentage(value);
5050 let lp = LengthPercentage::Percentage(pc);
5051 let lp_or_auto = LengthPercentageOrAuto::LengthPercentage(lp.clone());
5052
5053 let prop = match_wrap_declared! { long,
5054 Height => Size::LengthPercentage(NonNegative(lp)),
5055 Width => Size::LengthPercentage(NonNegative(lp)),
5056 X => lp,
5057 Y => lp,
5058 Cx => lp,
5059 Cy => lp,
5060 R => NonNegative(lp),
5061 Rx => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5062 Ry => LengthPercentageOrAuto::LengthPercentage(NonNegative(lp)),
5063 MarginTop => lp_or_auto,
5064 MarginRight => lp_or_auto,
5065 MarginBottom => lp_or_auto,
5066 MarginLeft => lp_or_auto,
5067 FontSize => FontSize::Length(LengthPercentage::Percentage(pc)),
5068 };
5069 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5070 decls.push(prop, Importance::Normal);
5071 })
5072 }
5073
5074 #[no_mangle]
Servo_DeclarationBlock_SetAutoValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, )5075 pub extern "C" fn Servo_DeclarationBlock_SetAutoValue(
5076 declarations: &RawServoDeclarationBlock,
5077 property: nsCSSPropertyID,
5078 ) {
5079 use style::properties::PropertyDeclaration;
5080 use style::values::generics::length::{LengthPercentageOrAuto, Size};
5081
5082 let long = get_longhand_from_id!(property);
5083 let auto = LengthPercentageOrAuto::Auto;
5084
5085 let prop = match_wrap_declared! { long,
5086 Height => Size::auto(),
5087 Width => Size::auto(),
5088 MarginTop => auto,
5089 MarginRight => auto,
5090 MarginBottom => auto,
5091 MarginLeft => auto,
5092 };
5093 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5094 decls.push(prop, Importance::Normal);
5095 })
5096 }
5097
5098 #[no_mangle]
Servo_DeclarationBlock_SetCurrentColor( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, )5099 pub extern "C" fn Servo_DeclarationBlock_SetCurrentColor(
5100 declarations: &RawServoDeclarationBlock,
5101 property: nsCSSPropertyID,
5102 ) {
5103 use style::properties::PropertyDeclaration;
5104 use style::values::specified::Color;
5105
5106 let long = get_longhand_from_id!(property);
5107 let cc = Color::currentcolor();
5108
5109 let prop = match_wrap_declared! { long,
5110 BorderTopColor => cc,
5111 BorderRightColor => cc,
5112 BorderBottomColor => cc,
5113 BorderLeftColor => cc,
5114 };
5115 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5116 decls.push(prop, Importance::Normal);
5117 })
5118 }
5119
5120 #[no_mangle]
Servo_DeclarationBlock_SetColorValue( declarations: &RawServoDeclarationBlock, property: nsCSSPropertyID, value: structs::nscolor, )5121 pub extern "C" fn Servo_DeclarationBlock_SetColorValue(
5122 declarations: &RawServoDeclarationBlock,
5123 property: nsCSSPropertyID,
5124 value: structs::nscolor,
5125 ) {
5126 use style::gecko::values::convert_nscolor_to_rgba;
5127 use style::properties::longhands;
5128 use style::properties::PropertyDeclaration;
5129 use style::values::specified::Color;
5130
5131 let long = get_longhand_from_id!(property);
5132 let rgba = convert_nscolor_to_rgba(value);
5133 let color = Color::rgba(rgba);
5134
5135 let prop = match_wrap_declared! { long,
5136 BorderTopColor => color,
5137 BorderRightColor => color,
5138 BorderBottomColor => color,
5139 BorderLeftColor => color,
5140 Color => longhands::color::SpecifiedValue(color),
5141 BackgroundColor => color,
5142 };
5143 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5144 decls.push(prop, Importance::Normal);
5145 })
5146 }
5147
5148 #[no_mangle]
Servo_DeclarationBlock_SetFontFamily( declarations: &RawServoDeclarationBlock, value: &nsAString, )5149 pub extern "C" fn Servo_DeclarationBlock_SetFontFamily(
5150 declarations: &RawServoDeclarationBlock,
5151 value: &nsAString,
5152 ) {
5153 use style::properties::longhands::font_family::SpecifiedValue as FontFamily;
5154 use style::properties::PropertyDeclaration;
5155
5156 let string = value.to_string();
5157 let mut input = ParserInput::new(&string);
5158 let mut parser = Parser::new(&mut input);
5159 let result = FontFamily::parse_specified(&mut parser);
5160 if let Ok(family) = result {
5161 if parser.is_exhausted() {
5162 let decl = PropertyDeclaration::FontFamily(family);
5163 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5164 decls.push(decl, Importance::Normal);
5165 })
5166 }
5167 }
5168 }
5169
5170 #[no_mangle]
Servo_DeclarationBlock_SetBackgroundImage( declarations: &RawServoDeclarationBlock, value: &nsAString, raw_extra_data: *mut URLExtraData, )5171 pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
5172 declarations: &RawServoDeclarationBlock,
5173 value: &nsAString,
5174 raw_extra_data: *mut URLExtraData,
5175 ) {
5176 use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
5177 use style::properties::PropertyDeclaration;
5178 use style::stylesheets::CorsMode;
5179 use style::values::generics::image::Image;
5180 use style::values::specified::url::SpecifiedImageUrl;
5181
5182 let url_data = unsafe { UrlExtraData::from_ptr_ref(&raw_extra_data) };
5183 let string = value.to_string();
5184 let context = ParserContext::new(
5185 Origin::Author,
5186 url_data,
5187 Some(CssRuleType::Style),
5188 ParsingMode::DEFAULT,
5189 QuirksMode::NoQuirks,
5190 None,
5191 None,
5192 );
5193 let url = SpecifiedImageUrl::parse_from_string(string.into(), &context, CorsMode::None);
5194 let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
5195 vec![Image::Url(url)].into(),
5196 ));
5197 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5198 decls.push(decl, Importance::Normal);
5199 });
5200 }
5201
5202 #[no_mangle]
Servo_DeclarationBlock_SetTextDecorationColorOverride( declarations: &RawServoDeclarationBlock, )5203 pub extern "C" fn Servo_DeclarationBlock_SetTextDecorationColorOverride(
5204 declarations: &RawServoDeclarationBlock,
5205 ) {
5206 use style::properties::PropertyDeclaration;
5207 use style::values::specified::text::TextDecorationLine;
5208
5209 let decoration = TextDecorationLine::COLOR_OVERRIDE;
5210 let decl = PropertyDeclaration::TextDecorationLine(decoration);
5211 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5212 decls.push(decl, Importance::Normal);
5213 })
5214 }
5215
5216 #[no_mangle]
Servo_DeclarationBlock_SetAspectRatio( declarations: &RawServoDeclarationBlock, width: f32, height: f32, )5217 pub extern "C" fn Servo_DeclarationBlock_SetAspectRatio(
5218 declarations: &RawServoDeclarationBlock,
5219 width: f32,
5220 height: f32,
5221 ) {
5222 use style::properties::PropertyDeclaration;
5223 use style::values::generics::position::AspectRatio;
5224
5225 let decl = PropertyDeclaration::AspectRatio(AspectRatio::from_mapped_ratio(width, height));
5226 write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
5227 decls.push(decl, Importance::Normal);
5228 })
5229 }
5230
5231 #[no_mangle]
Servo_CSSSupports2( property: &nsACString, value: &nsACString, ) -> bool5232 pub unsafe extern "C" fn Servo_CSSSupports2(
5233 property: &nsACString,
5234 value: &nsACString,
5235 ) -> bool {
5236 let id = get_property_id_from_property!(property, false);
5237
5238 let mut declarations = SourcePropertyDeclaration::new();
5239 parse_property_into(
5240 &mut declarations,
5241 id,
5242 value,
5243 DUMMY_URL_DATA,
5244 structs::ParsingMode_Default,
5245 QuirksMode::NoQuirks,
5246 None,
5247 )
5248 .is_ok()
5249 }
5250
5251 #[no_mangle]
Servo_CSSSupports(cond: &nsACString) -> bool5252 pub extern "C" fn Servo_CSSSupports(cond: &nsACString) -> bool {
5253 let condition = unsafe { cond.as_str_unchecked() };
5254 let mut input = ParserInput::new(&condition);
5255 let mut input = Parser::new(&mut input);
5256 let cond = match input.parse_entirely(parse_condition_or_declaration) {
5257 Ok(c) => c,
5258 Err(..) => return false,
5259 };
5260
5261 let url_data = unsafe { dummy_url_data() };
5262
5263 // NOTE(emilio): The supports API is not associated to any stylesheet,
5264 // so the fact that there is no namespace map here is fine.
5265 let context = ParserContext::new_for_cssom(
5266 url_data,
5267 Some(CssRuleType::Style),
5268 ParsingMode::DEFAULT,
5269 QuirksMode::NoQuirks,
5270 None,
5271 None,
5272 );
5273
5274 let namespaces = Default::default();
5275 cond.eval(&context, &namespaces)
5276 }
5277
5278 #[no_mangle]
Servo_NoteExplicitHints( element: &RawGeckoElement, restyle_hint: RestyleHint, change_hint: nsChangeHint, )5279 pub unsafe extern "C" fn Servo_NoteExplicitHints(
5280 element: &RawGeckoElement,
5281 restyle_hint: RestyleHint,
5282 change_hint: nsChangeHint,
5283 ) {
5284 GeckoElement(element).note_explicit_hints(restyle_hint, change_hint);
5285 }
5286
5287 #[no_mangle]
Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: *mut bool) -> u325288 pub extern "C" fn Servo_TakeChangeHint(element: &RawGeckoElement, was_restyled: *mut bool) -> u32 {
5289 let was_restyled = unsafe { was_restyled.as_mut().unwrap() };
5290 let element = GeckoElement(element);
5291
5292 let damage = match element.mutate_data() {
5293 Some(mut data) => {
5294 *was_restyled = data.is_restyle();
5295
5296 let damage = data.damage;
5297 data.clear_restyle_state();
5298 damage
5299 },
5300 None => {
5301 warn!("Trying to get change hint from unstyled element");
5302 *was_restyled = false;
5303 GeckoRestyleDamage::empty()
5304 },
5305 };
5306
5307 debug!("Servo_TakeChangeHint: {:?}, damage={:?}", element, damage);
5308 // We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
5309 // work as return values with the Linux 32-bit ABI at the moment because
5310 // they wrap the value in a struct, so for now just unwrap it.
5311 damage.as_change_hint().0
5312 }
5313
5314 #[no_mangle]
Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues>5315 pub extern "C" fn Servo_ResolveStyle(element: &RawGeckoElement) -> Strong<ComputedValues> {
5316 let element = GeckoElement(element);
5317 debug!("Servo_ResolveStyle: {:?}", element);
5318 let data = element
5319 .borrow_data()
5320 .expect("Resolving style on unstyled element");
5321
5322 debug_assert!(
5323 element.has_current_styles(&*data),
5324 "Resolving style on {:?} without current styles: {:?}",
5325 element,
5326 data
5327 );
5328 data.styles.primary().clone().into()
5329 }
5330
5331 #[no_mangle]
Servo_ResolveStyleLazily( element: &RawGeckoElement, pseudo_type: PseudoStyleType, rule_inclusion: StyleRuleInclusion, snapshots: *const ServoElementSnapshotTable, raw_data: &RawServoStyleSet, ) -> Strong<ComputedValues>5332 pub extern "C" fn Servo_ResolveStyleLazily(
5333 element: &RawGeckoElement,
5334 pseudo_type: PseudoStyleType,
5335 rule_inclusion: StyleRuleInclusion,
5336 snapshots: *const ServoElementSnapshotTable,
5337 raw_data: &RawServoStyleSet,
5338 ) -> Strong<ComputedValues> {
5339 debug_assert!(!snapshots.is_null());
5340 let global_style_data = &*GLOBAL_STYLE_DATA;
5341 let guard = global_style_data.shared_lock.read();
5342 let element = GeckoElement(element);
5343 let doc_data = PerDocumentStyleData::from_ffi(raw_data);
5344 let data = doc_data.borrow();
5345 let rule_inclusion = RuleInclusion::from(rule_inclusion);
5346 let pseudo = PseudoElement::from_pseudo_type(pseudo_type);
5347 let finish = |styles: &ElementStyles, is_probe: bool| -> Option<Arc<ComputedValues>> {
5348 match pseudo {
5349 Some(ref pseudo) => {
5350 get_pseudo_style(
5351 &guard,
5352 element,
5353 pseudo,
5354 rule_inclusion,
5355 styles,
5356 /* inherited_styles = */ None,
5357 &*data,
5358 is_probe,
5359 /* matching_func = */ None,
5360 )
5361 },
5362 None => Some(styles.primary().clone()),
5363 }
5364 };
5365
5366 let is_before_or_after = pseudo.as_ref().map_or(false, |p| p.is_before_or_after());
5367
5368 // In the common case we already have the style. Check that before setting
5369 // up all the computation machinery.
5370 //
5371 // Also, only probe in the ::before or ::after case, since their styles may
5372 // not be in the `ElementData`, given they may exist but not be applicable
5373 // to generate an actual pseudo-element (like, having a `content: none`).
5374 if rule_inclusion == RuleInclusion::All {
5375 let styles = element.mutate_data().and_then(|d| {
5376 if d.has_styles() {
5377 finish(&d.styles, is_before_or_after)
5378 } else {
5379 None
5380 }
5381 });
5382 if let Some(result) = styles {
5383 return result.into();
5384 }
5385 }
5386
5387 // We don't have the style ready. Go ahead and compute it as necessary.
5388 let shared = create_shared_context(
5389 &global_style_data,
5390 &guard,
5391 &data,
5392 TraversalFlags::empty(),
5393 unsafe { &*snapshots },
5394 );
5395 let mut tlc = ThreadLocalStyleContext::new(&shared);
5396 let mut context = StyleContext {
5397 shared: &shared,
5398 thread_local: &mut tlc,
5399 };
5400
5401 let styles = resolve_style(&mut context, element, rule_inclusion, pseudo.as_ref());
5402
5403 finish(&styles, /* is_probe = */ false)
5404 .expect("We're not probing, so we should always get a style back")
5405 .into()
5406 }
5407
5408 #[no_mangle]
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>5409 pub extern "C" fn Servo_ReparentStyle(
5410 style_to_reparent: &ComputedValues,
5411 parent_style: &ComputedValues,
5412 parent_style_ignoring_first_line: &ComputedValues,
5413 layout_parent_style: &ComputedValues,
5414 element: Option<&RawGeckoElement>,
5415 raw_data: &RawServoStyleSet,
5416 ) -> Strong<ComputedValues> {
5417 let global_style_data = &*GLOBAL_STYLE_DATA;
5418 let guard = global_style_data.shared_lock.read();
5419 let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5420 let inputs = CascadeInputs::new_from_style(style_to_reparent);
5421 let metrics = get_metrics_provider_for_product();
5422 let pseudo = style_to_reparent.pseudo();
5423 let element = element.map(GeckoElement);
5424
5425 doc_data
5426 .stylist
5427 .cascade_style_and_visited(
5428 element,
5429 pseudo.as_ref(),
5430 inputs,
5431 &StylesheetGuards::same(&guard),
5432 Some(parent_style),
5433 Some(parent_style_ignoring_first_line),
5434 Some(layout_parent_style),
5435 &metrics,
5436 /* rule_cache = */ None,
5437 &mut RuleCacheConditions::default(),
5438 )
5439 .into()
5440 }
5441
5442 #[cfg(feature = "gecko_debug")]
simulate_compute_values_failure(property: &PropertyValuePair) -> bool5443 fn simulate_compute_values_failure(property: &PropertyValuePair) -> bool {
5444 let p = property.mProperty;
5445 let id = get_property_id_from_nscsspropertyid!(p, false);
5446 id.as_shorthand().is_ok() && property.mSimulateComputeValuesFailure
5447 }
5448
5449 #[cfg(not(feature = "gecko_debug"))]
simulate_compute_values_failure(_: &PropertyValuePair) -> bool5450 fn simulate_compute_values_failure(_: &PropertyValuePair) -> bool {
5451 false
5452 }
5453
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>5454 fn create_context_for_animation<'a>(
5455 per_doc_data: &'a PerDocumentStyleDataImpl,
5456 font_metrics_provider: &'a dyn FontMetricsProvider,
5457 style: &'a ComputedValues,
5458 parent_style: Option<&'a ComputedValues>,
5459 for_smil_animation: bool,
5460 rule_cache_conditions: &'a mut RuleCacheConditions,
5461 ) -> Context<'a> {
5462 Context {
5463 builder: StyleBuilder::for_animation(per_doc_data.stylist.device(), style, parent_style),
5464 font_metrics_provider: font_metrics_provider,
5465 cached_system_font: None,
5466 in_media_query: false,
5467 quirks_mode: per_doc_data.stylist.quirks_mode(),
5468 for_smil_animation,
5469 for_non_inherited_property: None,
5470 rule_cache_conditions: RefCell::new(rule_cache_conditions),
5471 }
5472 }
5473
5474 struct PropertyAndIndex {
5475 property: PropertyId,
5476 index: usize,
5477 }
5478
5479 struct PrioritizedPropertyIter<'a> {
5480 properties: &'a [PropertyValuePair],
5481 sorted_property_indices: Vec<PropertyAndIndex>,
5482 curr: usize,
5483 }
5484
5485 impl<'a> PrioritizedPropertyIter<'a> {
new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter5486 fn new(properties: &'a [PropertyValuePair]) -> PrioritizedPropertyIter {
5487 use style::values::animated::compare_property_priority;
5488
5489 // If we fail to convert a nsCSSPropertyID into a PropertyId we
5490 // shouldn't fail outright but instead by treating that property as the
5491 // 'all' property we make it sort last.
5492 let mut sorted_property_indices: Vec<PropertyAndIndex> = properties
5493 .iter()
5494 .enumerate()
5495 .map(|(index, pair)| {
5496 let property = PropertyId::from_nscsspropertyid(pair.mProperty)
5497 .unwrap_or(PropertyId::Shorthand(ShorthandId::All));
5498
5499 PropertyAndIndex { property, index }
5500 })
5501 .collect();
5502 sorted_property_indices.sort_by(|a, b| compare_property_priority(&a.property, &b.property));
5503
5504 PrioritizedPropertyIter {
5505 properties,
5506 sorted_property_indices,
5507 curr: 0,
5508 }
5509 }
5510 }
5511
5512 impl<'a> Iterator for PrioritizedPropertyIter<'a> {
5513 type Item = &'a PropertyValuePair;
5514
next(&mut self) -> Option<&'a PropertyValuePair>5515 fn next(&mut self) -> Option<&'a PropertyValuePair> {
5516 if self.curr >= self.sorted_property_indices.len() {
5517 return None;
5518 }
5519 self.curr += 1;
5520 Some(&self.properties[self.sorted_property_indices[self.curr - 1].index])
5521 }
5522 }
5523
5524 #[no_mangle]
Servo_GetComputedKeyframeValues( keyframes: &nsTArray<structs::Keyframe>, element: &RawGeckoElement, style: &ComputedValues, raw_data: &RawServoStyleSet, computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>, )5525 pub extern "C" fn Servo_GetComputedKeyframeValues(
5526 keyframes: &nsTArray<structs::Keyframe>,
5527 element: &RawGeckoElement,
5528 style: &ComputedValues,
5529 raw_data: &RawServoStyleSet,
5530 computed_keyframes: &mut nsTArray<structs::ComputedKeyframeValues>,
5531 ) {
5532 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5533 let metrics = get_metrics_provider_for_product();
5534
5535 let element = GeckoElement(element);
5536 let parent_element = element.inheritance_parent();
5537 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5538 let parent_style = parent_data
5539 .as_ref()
5540 .map(|d| d.styles.primary())
5541 .map(|x| &**x);
5542
5543 let mut conditions = Default::default();
5544 let mut context = create_context_for_animation(
5545 &data,
5546 &metrics,
5547 &style,
5548 parent_style,
5549 /* for_smil_animation = */ false,
5550 &mut conditions,
5551 );
5552
5553 let global_style_data = &*GLOBAL_STYLE_DATA;
5554 let guard = global_style_data.shared_lock.read();
5555 let default_values = data.default_computed_values();
5556
5557 let mut raw_custom_properties_block; // To make the raw block alive in the scope.
5558 for (index, keyframe) in keyframes.iter().enumerate() {
5559 let mut custom_properties = None;
5560 for property in keyframe.mPropertyValues.iter() {
5561 // Find the block for custom properties first.
5562 if property.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable {
5563 raw_custom_properties_block =
5564 unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
5565 let guard =
5566 Locked::<PropertyDeclarationBlock>::as_arc(&raw_custom_properties_block)
5567 .read_with(&guard);
5568 custom_properties = guard.cascade_custom_properties_with_context(&context);
5569 // There should be one PropertyDeclarationBlock for custom properties.
5570 break;
5571 }
5572 }
5573
5574 let ref mut animation_values = computed_keyframes[index];
5575
5576 let mut seen = LonghandIdSet::new();
5577
5578 let mut property_index = 0;
5579 for property in PrioritizedPropertyIter::new(&keyframe.mPropertyValues) {
5580 if simulate_compute_values_failure(property) {
5581 continue;
5582 }
5583
5584 let mut maybe_append_animation_value =
5585 |property: LonghandId, value: Option<AnimationValue>| {
5586 debug_assert!(!property.is_logical());
5587 debug_assert!(property.is_animatable());
5588
5589 // 'display' is only animatable from SMIL
5590 if property == LonghandId::Display {
5591 return;
5592 }
5593
5594 if seen.contains(property) {
5595 return;
5596 }
5597 seen.insert(property);
5598
5599 // This is safe since we immediately write to the uninitialized values.
5600 unsafe { animation_values.set_len((property_index + 1) as u32) };
5601 animation_values[property_index].mProperty = property.to_nscsspropertyid();
5602 match value {
5603 Some(v) => {
5604 animation_values[property_index]
5605 .mValue
5606 .mServo
5607 .set_arc_leaky(Arc::new(v));
5608 },
5609 None => {
5610 animation_values[property_index].mValue.mServo.mRawPtr =
5611 ptr::null_mut();
5612 },
5613 }
5614 property_index += 1;
5615 };
5616
5617 if property.mServoDeclarationBlock.mRawPtr.is_null() {
5618 let property = LonghandId::from_nscsspropertyid(property.mProperty);
5619 if let Ok(prop) = property {
5620 maybe_append_animation_value(prop, None);
5621 }
5622 continue;
5623 }
5624
5625 let declarations = unsafe { &*property.mServoDeclarationBlock.mRawPtr.clone() };
5626 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5627 let guard = declarations.read_with(&guard);
5628 let iter = guard.to_animation_value_iter(
5629 &mut context,
5630 &default_values,
5631 custom_properties.as_ref(),
5632 );
5633
5634 for value in iter {
5635 let id = value.id();
5636 maybe_append_animation_value(id, Some(value));
5637 }
5638 }
5639 }
5640 }
5641
5642 #[no_mangle]
Servo_GetAnimationValues( declarations: &RawServoDeclarationBlock, element: &RawGeckoElement, style: &ComputedValues, raw_data: &RawServoStyleSet, animation_values: &mut nsTArray<structs::RefPtr<structs::RawServoAnimationValue>>, )5643 pub extern "C" fn Servo_GetAnimationValues(
5644 declarations: &RawServoDeclarationBlock,
5645 element: &RawGeckoElement,
5646 style: &ComputedValues,
5647 raw_data: &RawServoStyleSet,
5648 animation_values: &mut nsTArray<structs::RefPtr<structs::RawServoAnimationValue>>,
5649 ) {
5650 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5651 let metrics = get_metrics_provider_for_product();
5652
5653 let element = GeckoElement(element);
5654 let parent_element = element.inheritance_parent();
5655 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5656 let parent_style = parent_data
5657 .as_ref()
5658 .map(|d| d.styles.primary())
5659 .map(|x| &**x);
5660
5661 let mut conditions = Default::default();
5662 let mut context = create_context_for_animation(
5663 &data,
5664 &metrics,
5665 &style,
5666 parent_style,
5667 /* for_smil_animation = */ true,
5668 &mut conditions,
5669 );
5670
5671 let default_values = data.default_computed_values();
5672 let global_style_data = &*GLOBAL_STYLE_DATA;
5673 let guard = global_style_data.shared_lock.read();
5674
5675 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5676 let guard = declarations.read_with(&guard);
5677 let iter = guard.to_animation_value_iter(
5678 &mut context,
5679 &default_values,
5680 None, // SMIL has no extra custom properties.
5681 );
5682 for (index, anim) in iter.enumerate() {
5683 unsafe { animation_values.set_len((index + 1) as u32) };
5684 animation_values[index].set_arc_leaky(Arc::new(anim));
5685 }
5686 }
5687
5688 #[no_mangle]
Servo_AnimationValue_GetPropertyId( value: &RawServoAnimationValue, ) -> nsCSSPropertyID5689 pub extern "C" fn Servo_AnimationValue_GetPropertyId(
5690 value: &RawServoAnimationValue,
5691 ) -> nsCSSPropertyID {
5692 let value = AnimationValue::as_arc(&value);
5693 value.id().to_nscsspropertyid()
5694 }
5695
5696 #[no_mangle]
Servo_AnimationValue_Compute( element: &RawGeckoElement, declarations: &RawServoDeclarationBlock, style: &ComputedValues, raw_data: &RawServoStyleSet, ) -> Strong<RawServoAnimationValue>5697 pub extern "C" fn Servo_AnimationValue_Compute(
5698 element: &RawGeckoElement,
5699 declarations: &RawServoDeclarationBlock,
5700 style: &ComputedValues,
5701 raw_data: &RawServoStyleSet,
5702 ) -> Strong<RawServoAnimationValue> {
5703 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5704 let metrics = get_metrics_provider_for_product();
5705
5706 let element = GeckoElement(element);
5707 let parent_element = element.inheritance_parent();
5708 let parent_data = parent_element.as_ref().and_then(|e| e.borrow_data());
5709 let parent_style = parent_data
5710 .as_ref()
5711 .map(|d| d.styles.primary())
5712 .map(|x| &**x);
5713
5714 let mut conditions = Default::default();
5715 let mut context = create_context_for_animation(
5716 &data,
5717 &metrics,
5718 style,
5719 parent_style,
5720 /* for_smil_animation = */ false,
5721 &mut conditions,
5722 );
5723
5724 let default_values = data.default_computed_values();
5725 let global_style_data = &*GLOBAL_STYLE_DATA;
5726 let guard = global_style_data.shared_lock.read();
5727 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
5728 // We only compute the first element in declarations.
5729 match declarations
5730 .read_with(&guard)
5731 .declaration_importance_iter()
5732 .next()
5733 {
5734 Some((decl, imp)) if imp == Importance::Normal => {
5735 let animation = AnimationValue::from_declaration(
5736 decl,
5737 &mut context,
5738 None, // No extra custom properties for devtools.
5739 default_values,
5740 );
5741 animation.map_or(Strong::null(), |value| Arc::new(value).into_strong())
5742 },
5743 _ => Strong::null(),
5744 }
5745 }
5746
5747 #[no_mangle]
Servo_AssertTreeIsClean(root: &RawGeckoElement)5748 pub extern "C" fn Servo_AssertTreeIsClean(root: &RawGeckoElement) {
5749 if !cfg!(feature = "gecko_debug") {
5750 panic!("Calling Servo_AssertTreeIsClean in release build");
5751 }
5752
5753 let root = GeckoElement(root);
5754 debug!("Servo_AssertTreeIsClean: ");
5755 debug!("{:?}", ShowSubtreeData(root.as_node()));
5756
5757 fn assert_subtree_is_clean<'le>(el: GeckoElement<'le>) {
5758 debug_assert!(
5759 !el.has_dirty_descendants() && !el.has_animation_only_dirty_descendants(),
5760 "{:?} has still dirty bit {:?} or animation-only dirty bit {:?}",
5761 el,
5762 el.has_dirty_descendants(),
5763 el.has_animation_only_dirty_descendants()
5764 );
5765 for child in el.traversal_children() {
5766 if let Some(child) = child.as_element() {
5767 assert_subtree_is_clean(child);
5768 }
5769 }
5770 }
5771
5772 assert_subtree_is_clean(root);
5773 }
5774
5775 #[no_mangle]
Servo_IsWorkerThread() -> bool5776 pub extern "C" fn Servo_IsWorkerThread() -> bool {
5777 thread_state::get().is_worker()
5778 }
5779
5780 enum Offset {
5781 Zero,
5782 One,
5783 }
5784
fill_in_missing_keyframe_values( all_properties: &LonghandIdSet, timing_function: &nsTimingFunction, longhands_at_offset: &LonghandIdSet, offset: Offset, keyframes: &mut nsTArray<structs::Keyframe>, )5785 fn fill_in_missing_keyframe_values(
5786 all_properties: &LonghandIdSet,
5787 timing_function: &nsTimingFunction,
5788 longhands_at_offset: &LonghandIdSet,
5789 offset: Offset,
5790 keyframes: &mut nsTArray<structs::Keyframe>,
5791 ) {
5792 // Return early if all animated properties are already set.
5793 if longhands_at_offset.contains_all(all_properties) {
5794 return;
5795 }
5796
5797 let keyframe = match offset {
5798 Offset::Zero => unsafe { Gecko_GetOrCreateInitialKeyframe(keyframes, timing_function) },
5799 Offset::One => unsafe { Gecko_GetOrCreateFinalKeyframe(keyframes, timing_function) },
5800 };
5801
5802 // Append properties that have not been set at this offset.
5803 for property in all_properties.iter() {
5804 if !longhands_at_offset.contains(property) {
5805 unsafe {
5806 Gecko_AppendPropertyValuePair(
5807 &mut *(*keyframe).mPropertyValues,
5808 property.to_nscsspropertyid(),
5809 );
5810 }
5811 }
5812 }
5813 }
5814
5815 #[no_mangle]
Servo_StyleSet_GetKeyframesForName( raw_data: &RawServoStyleSet, element: &RawGeckoElement, style: &ComputedValues, name: *mut nsAtom, inherited_timing_function: &nsTimingFunction, keyframes: &mut nsTArray<structs::Keyframe>, ) -> bool5816 pub unsafe extern "C" fn Servo_StyleSet_GetKeyframesForName(
5817 raw_data: &RawServoStyleSet,
5818 element: &RawGeckoElement,
5819 style: &ComputedValues,
5820 name: *mut nsAtom,
5821 inherited_timing_function: &nsTimingFunction,
5822 keyframes: &mut nsTArray<structs::Keyframe>,
5823 ) -> bool {
5824 debug_assert!(keyframes.len() == 0, "keyframes should be initially empty");
5825
5826 let element = GeckoElement(element);
5827 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
5828 let name = Atom::from_raw(name);
5829
5830 let animation = match data.stylist.get_animation(&name, element) {
5831 Some(animation) => animation,
5832 None => return false,
5833 };
5834
5835 let global_style_data = &*GLOBAL_STYLE_DATA;
5836 let guard = global_style_data.shared_lock.read();
5837
5838 let mut properties_set_at_current_offset = LonghandIdSet::new();
5839 let mut properties_set_at_start = LonghandIdSet::new();
5840 let mut properties_set_at_end = LonghandIdSet::new();
5841 let mut has_complete_initial_keyframe = false;
5842 let mut has_complete_final_keyframe = false;
5843 let mut current_offset = -1.;
5844
5845 let writing_mode = style.writing_mode;
5846
5847 // Iterate over the keyframe rules backwards so we can drop overridden
5848 // properties (since declarations in later rules override those in earlier
5849 // ones).
5850 for step in animation.steps.iter().rev() {
5851 if step.start_percentage.0 != current_offset {
5852 properties_set_at_current_offset.clear();
5853 current_offset = step.start_percentage.0;
5854 }
5855
5856 // Override timing_function if the keyframe has an animation-timing-function.
5857 let timing_function = nsTimingFunction {
5858 mTiming: match step.get_animation_timing_function(&guard) {
5859 Some(val) => val.to_computed_value_without_context(),
5860 None => (*inherited_timing_function).mTiming,
5861 },
5862 };
5863
5864 // Look for an existing keyframe with the same offset and timing
5865 // function or else add a new keyframe at the beginning of the keyframe
5866 // array.
5867 let keyframe = Gecko_GetOrCreateKeyframeAtStart(
5868 keyframes,
5869 step.start_percentage.0 as f32,
5870 &timing_function,
5871 );
5872
5873 match step.value {
5874 KeyframesStepValue::ComputedValues => {
5875 // In KeyframesAnimation::from_keyframes if there is no 0% or
5876 // 100% keyframe at all, we will create a 'ComputedValues' step
5877 // to represent that all properties animated by the keyframes
5878 // animation should be set to the underlying computed value for
5879 // that keyframe.
5880 let mut seen = LonghandIdSet::new();
5881 for property in animation.properties_changed.iter() {
5882 let property = property.to_physical(writing_mode);
5883 if seen.contains(property) {
5884 continue;
5885 }
5886 seen.insert(property);
5887
5888 Gecko_AppendPropertyValuePair(
5889 &mut *(*keyframe).mPropertyValues,
5890 property.to_nscsspropertyid(),
5891 );
5892 }
5893 if current_offset == 0.0 {
5894 has_complete_initial_keyframe = true;
5895 } else if current_offset == 1.0 {
5896 has_complete_final_keyframe = true;
5897 }
5898 },
5899 KeyframesStepValue::Declarations { ref block } => {
5900 let guard = block.read_with(&guard);
5901
5902 let mut custom_properties = PropertyDeclarationBlock::new();
5903
5904 // Filter out non-animatable properties and properties with
5905 // !important.
5906 //
5907 // Also, iterate in reverse to respect the source order in case
5908 // there are logical and physical longhands in the same block.
5909 for declaration in guard.normal_declaration_iter().rev() {
5910 let id = declaration.id();
5911
5912 let id = match id {
5913 PropertyDeclarationId::Longhand(id) => {
5914 // Skip the 'display' property because although it
5915 // is animatable from SMIL, it should not be
5916 // animatable from CSS Animations.
5917 if id == LonghandId::Display {
5918 continue;
5919 }
5920
5921 if !id.is_animatable() {
5922 continue;
5923 }
5924
5925 id.to_physical(writing_mode)
5926 },
5927 PropertyDeclarationId::Custom(..) => {
5928 custom_properties.push(declaration.clone(), Importance::Normal);
5929 continue;
5930 },
5931 };
5932
5933 if properties_set_at_current_offset.contains(id) {
5934 continue;
5935 }
5936
5937 let pair = Gecko_AppendPropertyValuePair(
5938 &mut *(*keyframe).mPropertyValues,
5939 id.to_nscsspropertyid(),
5940 );
5941
5942 (*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
5943 global_style_data
5944 .shared_lock
5945 .wrap(PropertyDeclarationBlock::with_one(
5946 declaration.to_physical(writing_mode),
5947 Importance::Normal,
5948 )),
5949 ));
5950
5951 if current_offset == 0.0 {
5952 properties_set_at_start.insert(id);
5953 } else if current_offset == 1.0 {
5954 properties_set_at_end.insert(id);
5955 }
5956 properties_set_at_current_offset.insert(id);
5957 }
5958
5959 if custom_properties.any_normal() {
5960 let pair = Gecko_AppendPropertyValuePair(
5961 &mut *(*keyframe).mPropertyValues,
5962 nsCSSPropertyID::eCSSPropertyExtra_variable,
5963 );
5964
5965 (*pair).mServoDeclarationBlock.set_arc_leaky(Arc::new(
5966 global_style_data.shared_lock.wrap(custom_properties),
5967 ));
5968 }
5969 },
5970 }
5971 }
5972
5973 let mut properties_changed = LonghandIdSet::new();
5974 for property in animation.properties_changed.iter() {
5975 properties_changed.insert(property.to_physical(writing_mode));
5976 }
5977
5978 // Append property values that are missing in the initial or the final keyframes.
5979 if !has_complete_initial_keyframe {
5980 fill_in_missing_keyframe_values(
5981 &properties_changed,
5982 inherited_timing_function,
5983 &properties_set_at_start,
5984 Offset::Zero,
5985 keyframes,
5986 );
5987 }
5988 if !has_complete_final_keyframe {
5989 fill_in_missing_keyframe_values(
5990 &properties_changed,
5991 inherited_timing_function,
5992 &properties_set_at_end,
5993 Offset::One,
5994 keyframes,
5995 );
5996 }
5997 true
5998 }
5999
6000 #[no_mangle]
Servo_StyleSet_GetFontFaceRules( raw_data: &RawServoStyleSet, rules: &mut nsTArray<structs::nsFontFaceRuleContainer>, )6001 pub extern "C" fn Servo_StyleSet_GetFontFaceRules(
6002 raw_data: &RawServoStyleSet,
6003 rules: &mut nsTArray<structs::nsFontFaceRuleContainer>,
6004 ) {
6005 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6006 debug_assert_eq!(rules.len(), 0);
6007
6008 let len: u32 = data
6009 .stylist
6010 .iter_extra_data_origins()
6011 .map(|(d, _)| d.font_faces.len() as u32)
6012 .sum();
6013
6014 // Reversed iterator because Gecko expects rules to appear sorted
6015 // UserAgent first, Author last.
6016 let font_face_iter = data
6017 .stylist
6018 .iter_extra_data_origins_rev()
6019 .flat_map(|(d, o)| d.font_faces.iter().zip(iter::repeat(o)));
6020
6021 unsafe { rules.set_len(len) };
6022 for ((rule, origin), dest) in font_face_iter.zip(rules.iter_mut()) {
6023 dest.mRule.set_arc_leaky(rule.clone());
6024 dest.mOrigin = origin;
6025 }
6026 }
6027
6028 // XXX Ideally this should return a Option<&RawServoCounterStyleRule>,
6029 // but we cannot, because the value from AtomicRefCell::borrow() can only
6030 // live in this function, and thus anything derived from it cannot get the
6031 // same lifetime as raw_data in parameter. See bug 1451543.
6032 #[no_mangle]
Servo_StyleSet_GetCounterStyleRule( raw_data: &RawServoStyleSet, name: *mut nsAtom, ) -> *const RawServoCounterStyleRule6033 pub unsafe extern "C" fn Servo_StyleSet_GetCounterStyleRule(
6034 raw_data: &RawServoStyleSet,
6035 name: *mut nsAtom,
6036 ) -> *const RawServoCounterStyleRule {
6037 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6038 Atom::with(name, |name| {
6039 data.stylist
6040 .iter_extra_data_origins()
6041 .filter_map(|(d, _)| d.counter_styles.get(name))
6042 .next()
6043 .map_or(ptr::null(), |rule| rule.as_borrowed())
6044 })
6045 }
6046
6047 #[no_mangle]
Servo_StyleSet_BuildFontFeatureValueSet( raw_data: &RawServoStyleSet, ) -> *mut gfxFontFeatureValueSet6048 pub extern "C" fn Servo_StyleSet_BuildFontFeatureValueSet(
6049 raw_data: &RawServoStyleSet,
6050 ) -> *mut gfxFontFeatureValueSet {
6051 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6052
6053 let global_style_data = &*GLOBAL_STYLE_DATA;
6054 let guard = global_style_data.shared_lock.read();
6055
6056 let has_rule = data
6057 .stylist
6058 .iter_extra_data_origins()
6059 .any(|(d, _)| !d.font_feature_values.is_empty());
6060
6061 if !has_rule {
6062 return ptr::null_mut();
6063 }
6064
6065 let font_feature_values_iter = data
6066 .stylist
6067 .iter_extra_data_origins_rev()
6068 .flat_map(|(d, _)| d.font_feature_values.iter());
6069
6070 let set = unsafe { Gecko_ConstructFontFeatureValueSet() };
6071 for src in font_feature_values_iter {
6072 let rule = src.read_with(&guard);
6073 rule.set_at_rules(set);
6074 }
6075 set
6076 }
6077
6078 #[no_mangle]
Servo_StyleSet_ResolveForDeclarations( raw_data: &RawServoStyleSet, parent_style_context: Option<&ComputedValues>, declarations: &RawServoDeclarationBlock, ) -> Strong<ComputedValues>6079 pub extern "C" fn Servo_StyleSet_ResolveForDeclarations(
6080 raw_data: &RawServoStyleSet,
6081 parent_style_context: Option<&ComputedValues>,
6082 declarations: &RawServoDeclarationBlock,
6083 ) -> Strong<ComputedValues> {
6084 let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6085 let global_style_data = &*GLOBAL_STYLE_DATA;
6086 let guard = global_style_data.shared_lock.read();
6087 let guards = StylesheetGuards::same(&guard);
6088
6089 let parent_style = match parent_style_context {
6090 Some(parent) => &*parent,
6091 None => doc_data.default_computed_values(),
6092 };
6093
6094 let declarations = Locked::<PropertyDeclarationBlock>::as_arc(&declarations);
6095
6096 doc_data
6097 .stylist
6098 .compute_for_declarations::<GeckoElement>(&guards, parent_style, declarations.clone_arc())
6099 .into()
6100 }
6101
6102 #[no_mangle]
Servo_StyleSet_AddSizeOfExcludingThis( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sizes: *mut ServoStyleSetSizes, raw_data: &RawServoStyleSet, )6103 pub extern "C" fn Servo_StyleSet_AddSizeOfExcludingThis(
6104 malloc_size_of: GeckoMallocSizeOf,
6105 malloc_enclosing_size_of: GeckoMallocSizeOf,
6106 sizes: *mut ServoStyleSetSizes,
6107 raw_data: &RawServoStyleSet,
6108 ) {
6109 let data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
6110 let mut ops = MallocSizeOfOps::new(
6111 malloc_size_of.unwrap(),
6112 Some(malloc_enclosing_size_of.unwrap()),
6113 None,
6114 );
6115 let sizes = unsafe { sizes.as_mut() }.unwrap();
6116 data.add_size_of(&mut ops, sizes);
6117 }
6118
6119 #[no_mangle]
Servo_UACache_AddSizeOf( malloc_size_of: GeckoMallocSizeOf, malloc_enclosing_size_of: GeckoMallocSizeOf, sizes: *mut ServoStyleSetSizes, )6120 pub extern "C" fn Servo_UACache_AddSizeOf(
6121 malloc_size_of: GeckoMallocSizeOf,
6122 malloc_enclosing_size_of: GeckoMallocSizeOf,
6123 sizes: *mut ServoStyleSetSizes,
6124 ) {
6125 let mut ops = MallocSizeOfOps::new(
6126 malloc_size_of.unwrap(),
6127 Some(malloc_enclosing_size_of.unwrap()),
6128 None,
6129 );
6130 let sizes = unsafe { sizes.as_mut() }.unwrap();
6131 add_size_of_ua_cache(&mut ops, sizes);
6132 }
6133
6134 #[no_mangle]
Servo_StyleSet_MightHaveAttributeDependency( raw_data: &RawServoStyleSet, element: &RawGeckoElement, local_name: *mut nsAtom, ) -> bool6135 pub extern "C" fn Servo_StyleSet_MightHaveAttributeDependency(
6136 raw_data: &RawServoStyleSet,
6137 element: &RawGeckoElement,
6138 local_name: *mut nsAtom,
6139 ) -> bool {
6140 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6141 let element = GeckoElement(element);
6142
6143 unsafe {
6144 Atom::with(local_name, |atom| {
6145 data.stylist.any_applicable_rule_data(element, |data| {
6146 data.might_have_attribute_dependency(atom)
6147 })
6148 })
6149 }
6150 }
6151
6152 #[no_mangle]
Servo_StyleSet_HasStateDependency( raw_data: &RawServoStyleSet, element: &RawGeckoElement, state: u64, ) -> bool6153 pub extern "C" fn Servo_StyleSet_HasStateDependency(
6154 raw_data: &RawServoStyleSet,
6155 element: &RawGeckoElement,
6156 state: u64,
6157 ) -> bool {
6158 let element = GeckoElement(element);
6159
6160 let state = ElementState::from_bits_truncate(state);
6161 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6162
6163 data.stylist
6164 .any_applicable_rule_data(element, |data| data.has_state_dependency(state))
6165 }
6166
6167 #[no_mangle]
Servo_StyleSet_HasDocumentStateDependency( raw_data: &RawServoStyleSet, state: u64, ) -> bool6168 pub extern "C" fn Servo_StyleSet_HasDocumentStateDependency(
6169 raw_data: &RawServoStyleSet,
6170 state: u64,
6171 ) -> bool {
6172 let state = DocumentState::from_bits_truncate(state);
6173 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6174
6175 data.stylist.has_document_state_dependency(state)
6176 }
6177
6178 #[no_mangle]
Servo_GetPropertyValue( style: &ComputedValues, prop: nsCSSPropertyID, value: &mut nsAString, )6179 pub unsafe extern "C" fn Servo_GetPropertyValue(
6180 style: &ComputedValues,
6181 prop: nsCSSPropertyID,
6182 value: &mut nsAString,
6183 ) {
6184 if let Ok(longhand) = LonghandId::from_nscsspropertyid(prop) {
6185 style
6186 .get_longhand_property_value(longhand, &mut CssWriter::new(value))
6187 .unwrap();
6188 return;
6189 }
6190
6191 let shorthand =
6192 ShorthandId::from_nscsspropertyid(prop).expect("Not a shorthand nor a longhand?");
6193 let mut block = PropertyDeclarationBlock::new();
6194 // NOTE(emilio): We reuse the animation value machinery to avoid blowing up
6195 // code size, but may need to come up with something different if ever care
6196 // about supporting the cases that assert below. Fortunately we don't right
6197 // now.
6198 for longhand in shorthand.longhands() {
6199 debug_assert!(
6200 !longhand.is_logical(),
6201 "This won't quite do the right thing if we want to serialize \
6202 logical shorthands"
6203 );
6204 let animated = AnimationValue::from_computed_values(longhand, style).expect(
6205 "Somebody tried to serialize a shorthand with \
6206 non-animatable properties, would need more code \
6207 to do this",
6208 );
6209 block.push(animated.uncompute(), Importance::Normal);
6210 }
6211 block.shorthand_to_css(shorthand, value).unwrap();
6212 }
6213
6214 #[no_mangle]
Servo_GetCustomPropertyValue( computed_values: &ComputedValues, name: &nsACString, value: &mut nsAString, ) -> bool6215 pub unsafe extern "C" fn Servo_GetCustomPropertyValue(
6216 computed_values: &ComputedValues,
6217 name: &nsACString,
6218 value: &mut nsAString,
6219 ) -> bool {
6220 let custom_properties = match computed_values.custom_properties() {
6221 Some(p) => p,
6222 None => return false,
6223 };
6224
6225 let name = Atom::from(name.as_str_unchecked());
6226 let computed_value = match custom_properties.get(&name) {
6227 Some(v) => v,
6228 None => return false,
6229 };
6230
6231 computed_value.to_css(&mut CssWriter::new(value)).unwrap();
6232 true
6233 }
6234
6235 #[no_mangle]
Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u326236 pub extern "C" fn Servo_GetCustomPropertiesCount(computed_values: &ComputedValues) -> u32 {
6237 match computed_values.custom_properties() {
6238 Some(p) => p.len() as u32,
6239 None => 0,
6240 }
6241 }
6242
6243 #[no_mangle]
Servo_GetCustomPropertyNameAt( computed_values: &ComputedValues, index: u32, ) -> *mut nsAtom6244 pub extern "C" fn Servo_GetCustomPropertyNameAt(
6245 computed_values: &ComputedValues,
6246 index: u32,
6247 ) -> *mut nsAtom {
6248 let custom_properties = match computed_values.custom_properties() {
6249 Some(p) => p,
6250 None => return ptr::null_mut(),
6251 };
6252
6253 let property_name = match custom_properties.get_index(index as usize) {
6254 Some((key, _value)) => key,
6255 None => return ptr::null_mut(),
6256 };
6257
6258
6259 property_name.as_ptr()
6260 }
6261
6262 #[no_mangle]
Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool6263 pub extern "C" fn Servo_CssUrl_IsLocalRef(url: &url::CssUrl) -> bool {
6264 url.is_fragment()
6265 }
6266
6267 #[no_mangle]
Servo_ProcessInvalidations( set: &RawServoStyleSet, element: &RawGeckoElement, snapshots: *const ServoElementSnapshotTable, )6268 pub extern "C" fn Servo_ProcessInvalidations(
6269 set: &RawServoStyleSet,
6270 element: &RawGeckoElement,
6271 snapshots: *const ServoElementSnapshotTable,
6272 ) {
6273 debug_assert!(!snapshots.is_null());
6274
6275 let element = GeckoElement(element);
6276 debug_assert!(element.has_snapshot());
6277 debug_assert!(!element.handled_snapshot());
6278
6279 let mut data = element.mutate_data();
6280 debug_assert!(data.is_some());
6281
6282 let global_style_data = &*GLOBAL_STYLE_DATA;
6283 let guard = global_style_data.shared_lock.read();
6284 let per_doc_data = PerDocumentStyleData::from_ffi(set).borrow();
6285 let shared_style_context = create_shared_context(
6286 &global_style_data,
6287 &guard,
6288 &per_doc_data,
6289 TraversalFlags::empty(),
6290 unsafe { &*snapshots },
6291 );
6292 let mut data = data.as_mut().map(|d| &mut **d);
6293
6294 if let Some(ref mut data) = data {
6295 // FIXME(emilio): Ideally we could share the nth-index-cache across all
6296 // the elements?
6297 let result = data.invalidate_style_if_needed(
6298 element,
6299 &shared_style_context,
6300 None,
6301 &mut NthIndexCache::default(),
6302 );
6303
6304 if result.has_invalidated_siblings() {
6305 let parent = element
6306 .traversal_parent()
6307 .expect("How could we invalidate siblings without a common parent?");
6308 unsafe {
6309 parent.set_dirty_descendants();
6310 bindings::Gecko_NoteDirtySubtreeForInvalidation(parent.0);
6311 }
6312 } else if result.has_invalidated_descendants() {
6313 unsafe { bindings::Gecko_NoteDirtySubtreeForInvalidation(element.0) };
6314 } else if result.has_invalidated_self() {
6315 unsafe { bindings::Gecko_NoteDirtyElement(element.0) };
6316 }
6317 }
6318 }
6319
6320 #[no_mangle]
Servo_HasPendingRestyleAncestor( element: &RawGeckoElement, may_need_to_flush_layout: bool, ) -> bool6321 pub extern "C" fn Servo_HasPendingRestyleAncestor(
6322 element: &RawGeckoElement,
6323 may_need_to_flush_layout: bool,
6324 ) -> bool {
6325 let mut has_yet_to_be_styled = false;
6326 let mut element = Some(GeckoElement(element));
6327 while let Some(e) = element {
6328 if e.has_animations() {
6329 return true;
6330 }
6331
6332 // If the element needs a frame, it means that we haven't styled it yet
6333 // after it got inserted in the document, and thus we may need to do
6334 // that for transitions and animations to trigger.
6335 //
6336 // This is a fast path in the common case, but `has_yet_to_be_styled` is
6337 // the real check for this.
6338 if e.needs_frame() {
6339 return true;
6340 }
6341
6342 let data = e.borrow_data();
6343 if let Some(ref data) = data {
6344 if !data.hint.is_empty() {
6345 return true;
6346 }
6347 if has_yet_to_be_styled && !data.styles.is_display_none() {
6348 return true;
6349 }
6350 // Ideally, DOM mutations wouldn't affect layout trees of siblings.
6351 //
6352 // In practice, this can happen because Gecko deals pretty badly
6353 // with some kinds of content insertion and removals.
6354 //
6355 // If we may need to flush layout, we need frames to accurately
6356 // determine whether we'll actually flush, so if we have to
6357 // reconstruct we need to flush style, which is what will take care
6358 // of ensuring that frames are constructed, even if the style itself
6359 // is up-to-date.
6360 if may_need_to_flush_layout && data.damage.contains(GeckoRestyleDamage::reconstruct()) {
6361 return true;
6362 }
6363 }
6364 has_yet_to_be_styled = data.is_none();
6365
6366 element = e.traversal_parent();
6367 }
6368 false
6369 }
6370
6371 #[no_mangle]
Servo_SelectorList_Parse( selector_list: &nsACString, ) -> OwnedOrNull<RawServoSelectorList>6372 pub unsafe extern "C" fn Servo_SelectorList_Parse(
6373 selector_list: &nsACString,
6374 ) -> OwnedOrNull<RawServoSelectorList> {
6375 use style::selector_parser::SelectorParser;
6376
6377 let input = selector_list.as_str_unchecked();
6378 let selector_list = match SelectorParser::parse_author_origin_no_namespace(&input) {
6379 Ok(selector_list) => selector_list,
6380 Err(..) => return OwnedOrNull::null(),
6381 };
6382
6383 Box::new(selector_list).into_ffi().maybe()
6384 }
6385
6386 #[no_mangle]
Servo_SelectorList_Drop(list: *mut RawServoSelectorList)6387 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: *mut RawServoSelectorList) {
6388 SelectorList::drop_ffi(list)
6389 }
6390
parse_color( value: &str, error_reporter: Option<&dyn ParseErrorReporter>, ) -> Result<specified::Color, ()>6391 fn parse_color(
6392 value: &str,
6393 error_reporter: Option<&dyn ParseErrorReporter>,
6394 ) -> Result<specified::Color, ()> {
6395 let mut input = ParserInput::new(value);
6396 let mut parser = Parser::new(&mut input);
6397 let url_data = unsafe { dummy_url_data() };
6398 let context = ParserContext::new(
6399 Origin::Author,
6400 url_data,
6401 Some(CssRuleType::Style),
6402 ParsingMode::DEFAULT,
6403 QuirksMode::NoQuirks,
6404 error_reporter,
6405 None,
6406 );
6407
6408 let start_position = parser.position();
6409 parser
6410 .parse_entirely(|i| specified::Color::parse(&context, i))
6411 .map_err(|err| {
6412 if error_reporter.is_some() {
6413 match err.kind {
6414 ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {
6415 let location = err.location.clone();
6416 let error = ContextualParseError::UnsupportedValue(
6417 parser.slice_from(start_position),
6418 err,
6419 );
6420 context.log_css_error(location, error);
6421 },
6422 // Ignore other kinds of errors that might be reported, such as
6423 // ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken),
6424 // since Gecko doesn't report those to the error console.
6425 _ => {},
6426 }
6427 }
6428 })
6429 }
6430
6431 #[no_mangle]
Servo_IsValidCSSColor(value: &nsACString) -> bool6432 pub unsafe extern "C" fn Servo_IsValidCSSColor(value: &nsACString) -> bool {
6433 parse_color(value.as_str_unchecked(), None).is_ok()
6434 }
6435
6436 #[no_mangle]
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, ) -> bool6437 pub unsafe extern "C" fn Servo_ComputeColor(
6438 raw_data: Option<&RawServoStyleSet>,
6439 current_color: structs::nscolor,
6440 value: &nsACString,
6441 result_color: &mut structs::nscolor,
6442 was_current_color: *mut bool,
6443 loader: *mut Loader,
6444 ) -> bool {
6445 use style::gecko;
6446
6447 let current_color = gecko::values::convert_nscolor_to_rgba(current_color);
6448
6449 let reporter = loader.as_mut().and_then(|loader| {
6450 // Make an ErrorReporter that will report errors as being "from DOM".
6451 ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
6452 });
6453
6454 let specified_color = match parse_color(
6455 value.as_str_unchecked(),
6456 reporter.as_ref().map(|r| r as &dyn ParseErrorReporter),
6457 ) {
6458 Ok(c) => c,
6459 Err(..) => return false,
6460 };
6461
6462 let computed_color = match raw_data {
6463 Some(raw_data) => {
6464 let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6465 let device = data.stylist.device();
6466 let quirks_mode = data.stylist.quirks_mode();
6467 Context::for_media_query_evaluation(device, quirks_mode, |context| {
6468 specified_color.to_computed_color(Some(&context))
6469 })
6470 },
6471 None => specified_color.to_computed_color(None),
6472 };
6473
6474 let computed_color = match computed_color {
6475 Some(c) => c,
6476 None => return false,
6477 };
6478
6479 let rgba = computed_color.to_rgba(current_color);
6480 *result_color = gecko::values::convert_rgba_to_nscolor(&rgba);
6481
6482 if !was_current_color.is_null() {
6483 *was_current_color = computed_color.is_currentcolor();
6484 }
6485
6486 true
6487 }
6488
6489 #[no_mangle]
Servo_IntersectionObserverRootMargin_Parse( value: &nsAString, result: *mut IntersectionObserverRootMargin, ) -> bool6490 pub unsafe extern "C" fn Servo_IntersectionObserverRootMargin_Parse(
6491 value: &nsAString,
6492 result: *mut IntersectionObserverRootMargin,
6493 ) -> bool {
6494 let value = value.to_string();
6495 let result = result.as_mut().unwrap();
6496
6497 let mut input = ParserInput::new(&value);
6498 let mut parser = Parser::new(&mut input);
6499
6500 let url_data = dummy_url_data();
6501 let context = ParserContext::new(
6502 Origin::Author,
6503 url_data,
6504 Some(CssRuleType::Style),
6505 ParsingMode::DEFAULT,
6506 QuirksMode::NoQuirks,
6507 None,
6508 None,
6509 );
6510
6511 let margin = parser.parse_entirely(|p| IntersectionObserverRootMargin::parse(&context, p));
6512 match margin {
6513 Ok(margin) => {
6514 *result = margin;
6515 true
6516 },
6517 Err(..) => false,
6518 }
6519 }
6520
6521 #[no_mangle]
Servo_IntersectionObserverRootMargin_ToString( root_margin: &IntersectionObserverRootMargin, result: &mut nsAString, )6522 pub extern "C" fn Servo_IntersectionObserverRootMargin_ToString(
6523 root_margin: &IntersectionObserverRootMargin,
6524 result: &mut nsAString,
6525 ) {
6526 let mut writer = CssWriter::new(result);
6527 root_margin.to_css(&mut writer).unwrap();
6528 }
6529
6530 #[no_mangle]
Servo_ParseTransformIntoMatrix( value: &nsACString, contain_3d: &mut bool, result: &mut structs::Matrix4x4Components, ) -> bool6531 pub extern "C" fn Servo_ParseTransformIntoMatrix(
6532 value: &nsACString,
6533 contain_3d: &mut bool,
6534 result: &mut structs::Matrix4x4Components,
6535 ) -> bool {
6536 use style::properties::longhands::transform;
6537
6538 let string = unsafe { value.as_str_unchecked() };
6539 let mut input = ParserInput::new(&string);
6540 let mut parser = Parser::new(&mut input);
6541 let context = ParserContext::new(
6542 Origin::Author,
6543 unsafe { dummy_url_data() },
6544 Some(CssRuleType::Style),
6545 ParsingMode::DEFAULT,
6546 QuirksMode::NoQuirks,
6547 None,
6548 None,
6549 );
6550
6551 let transform = match parser.parse_entirely(|t| transform::parse(&context, t)) {
6552 Ok(t) => t,
6553 Err(..) => return false,
6554 };
6555
6556 let (m, is_3d) = match transform.to_transform_3d_matrix(None) {
6557 Ok(result) => result,
6558 Err(..) => return false,
6559 };
6560
6561 *result = m.to_row_major_array();
6562 *contain_3d = is_3d;
6563 true
6564 }
6565
6566 #[no_mangle]
Servo_ParseFontShorthandForMatching( value: &nsAString, data: *mut URLExtraData, family: &mut structs::RefPtr<structs::SharedFontList>, style: &mut ComputedFontStyleDescriptor, stretch: &mut f32, weight: &mut f32, ) -> bool6567 pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
6568 value: &nsAString,
6569 data: *mut URLExtraData,
6570 family: &mut structs::RefPtr<structs::SharedFontList>,
6571 style: &mut ComputedFontStyleDescriptor,
6572 stretch: &mut f32,
6573 weight: &mut f32,
6574 ) -> bool {
6575 use style::properties::shorthands::font;
6576 use style::values::computed::font::FontFamilyList;
6577 use style::values::computed::font::FontWeight as ComputedFontWeight;
6578 use style::values::generics::font::FontStyle as GenericFontStyle;
6579 use style::values::specified::font::{
6580 FontFamily, FontStretch, FontStyle, FontWeight, SpecifiedFontStyle,
6581 };
6582
6583 let string = value.to_string();
6584 let mut input = ParserInput::new(&string);
6585 let mut parser = Parser::new(&mut input);
6586 let url_data = UrlExtraData::from_ptr_ref(&data);
6587 let context = ParserContext::new(
6588 Origin::Author,
6589 url_data,
6590 Some(CssRuleType::FontFace),
6591 ParsingMode::DEFAULT,
6592 QuirksMode::NoQuirks,
6593 None,
6594 None,
6595 );
6596
6597 let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
6598 Ok(f) => f,
6599 Err(..) => return false,
6600 };
6601
6602 // The system font is not acceptable, so we return false.
6603 match font.font_family {
6604 FontFamily::Values(FontFamilyList::SharedFontList(list)) => family.set_move(list),
6605 FontFamily::Values(list) => family.set_move(list.shared_font_list().clone()),
6606 FontFamily::System(_) => return false,
6607 }
6608
6609 let specified_font_style = match font.font_style {
6610 FontStyle::Specified(ref s) => s,
6611 FontStyle::System(_) => return false,
6612 };
6613
6614 *style = match *specified_font_style {
6615 GenericFontStyle::Normal => ComputedFontStyleDescriptor::Normal,
6616 GenericFontStyle::Italic => ComputedFontStyleDescriptor::Italic,
6617 GenericFontStyle::Oblique(ref angle) => {
6618 let angle = SpecifiedFontStyle::compute_angle_degrees(angle);
6619 ComputedFontStyleDescriptor::Oblique(angle, angle)
6620 },
6621 };
6622
6623 *stretch = match font.font_stretch {
6624 FontStretch::Keyword(ref k) => k.compute().0,
6625 FontStretch::Stretch(ref p) => p.get(),
6626 FontStretch::System(_) => return false,
6627 };
6628
6629 *weight = match font.font_weight {
6630 FontWeight::Absolute(w) => w.compute().0,
6631 // Resolve relative font weights against the initial of font-weight
6632 // (normal, which is equivalent to 400).
6633 FontWeight::Bolder => ComputedFontWeight::normal().bolder().0,
6634 FontWeight::Lighter => ComputedFontWeight::normal().lighter().0,
6635 FontWeight::System(_) => return false,
6636 };
6637
6638 true
6639 }
6640
6641 #[no_mangle]
Servo_SourceSizeList_Parse( value: &nsACString, ) -> Owned<RawServoSourceSizeList>6642 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(
6643 value: &nsACString,
6644 ) -> Owned<RawServoSourceSizeList> {
6645 let value = value.as_str_unchecked();
6646 let mut input = ParserInput::new(value);
6647 let mut parser = Parser::new(&mut input);
6648
6649 let context = ParserContext::new(
6650 Origin::Author,
6651 dummy_url_data(),
6652 Some(CssRuleType::Style),
6653 ParsingMode::DEFAULT,
6654 QuirksMode::NoQuirks,
6655 None,
6656 None,
6657 );
6658
6659 // NB: Intentionally not calling parse_entirely.
6660 let list = SourceSizeList::parse(&context, &mut parser);
6661 Box::new(list).into_ffi()
6662 }
6663
6664 #[no_mangle]
Servo_SourceSizeList_Evaluate( raw_data: &RawServoStyleSet, list: Option<&RawServoSourceSizeList>, ) -> i326665 pub unsafe extern "C" fn Servo_SourceSizeList_Evaluate(
6666 raw_data: &RawServoStyleSet,
6667 list: Option<&RawServoSourceSizeList>,
6668 ) -> i32 {
6669 let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
6670 let device = doc_data.stylist.device();
6671 let quirks_mode = doc_data.stylist.quirks_mode();
6672
6673 let result = match list {
6674 Some(list) => SourceSizeList::from_ffi(list).evaluate(device, quirks_mode),
6675 None => SourceSizeList::empty().evaluate(device, quirks_mode),
6676 };
6677
6678 result.0
6679 }
6680
6681 #[no_mangle]
Servo_SourceSizeList_Drop(list: *mut RawServoSourceSizeList)6682 pub unsafe extern "C" fn Servo_SourceSizeList_Drop(list: *mut RawServoSourceSizeList) {
6683 SourceSizeList::drop_ffi(list);
6684 }
6685
6686 #[no_mangle]
Servo_InvalidateStyleForDocStateChanges( root: &RawGeckoElement, document_style: &RawServoStyleSet, non_document_styles: &nsTArray<&RawServoAuthorStyles>, states_changed: u64, )6687 pub unsafe extern "C" fn Servo_InvalidateStyleForDocStateChanges(
6688 root: &RawGeckoElement,
6689 document_style: &RawServoStyleSet,
6690 non_document_styles: &nsTArray<&RawServoAuthorStyles>,
6691 states_changed: u64,
6692 ) {
6693 use style::invalidation::element::document_state::DocumentStateInvalidationProcessor;
6694 use style::invalidation::element::invalidator::TreeStyleInvalidator;
6695
6696 let document_data = PerDocumentStyleData::from_ffi(document_style).borrow();
6697
6698 let iter = document_data
6699 .stylist
6700 .iter_origins()
6701 .map(|(data, _origin)| data)
6702 .chain(non_document_styles.iter().map(|author_styles| {
6703 let styles: &_ = AuthorStyles::<GeckoStyleSheet>::from_ffi(author_styles);
6704 &styles.data
6705 }));
6706
6707 let root = GeckoElement(root);
6708 let mut processor = DocumentStateInvalidationProcessor::new(
6709 iter,
6710 DocumentState::from_bits_truncate(states_changed),
6711 root.as_node().owner_doc().quirks_mode(),
6712 );
6713
6714 let result =
6715 TreeStyleInvalidator::new(root, /* stack_limit_checker = */ None, &mut processor)
6716 .invalidate();
6717
6718 debug_assert!(!result.has_invalidated_siblings(), "How in the world?");
6719 if result.has_invalidated_descendants() {
6720 bindings::Gecko_NoteDirtySubtreeForInvalidation(root.0);
6721 } else if result.has_invalidated_self() {
6722 bindings::Gecko_NoteDirtyElement(root.0);
6723 }
6724 }
6725
6726 #[no_mangle]
Servo_PseudoClass_GetStates(name: &nsACString) -> u646727 pub unsafe extern "C" fn Servo_PseudoClass_GetStates(name: &nsACString) -> u64 {
6728 let name = name.as_str_unchecked();
6729 match NonTSPseudoClass::parse_non_functional(name) {
6730 None => 0,
6731 // Ignore :any-link since it contains both visited and unvisited state.
6732 Some(NonTSPseudoClass::AnyLink) => 0,
6733 Some(pseudo_class) => pseudo_class.state_flag().bits(),
6734 }
6735 }
6736
6737 #[no_mangle]
Servo_UseCounters_Create() -> Owned<structs::StyleUseCounters>6738 pub unsafe extern "C" fn Servo_UseCounters_Create() -> Owned<structs::StyleUseCounters> {
6739 Box::<UseCounters>::default().into_ffi()
6740 }
6741
6742 #[no_mangle]
Servo_UseCounters_Drop(c: *mut structs::StyleUseCounters)6743 pub unsafe extern "C" fn Servo_UseCounters_Drop(c: *mut structs::StyleUseCounters) {
6744 UseCounters::drop_ffi(c);
6745 }
6746
6747 #[no_mangle]
Servo_UseCounters_Merge( doc_counters: &UseCounters, sheet_counters: &UseCounters, )6748 pub unsafe extern "C" fn Servo_UseCounters_Merge(
6749 doc_counters: &UseCounters,
6750 sheet_counters: &UseCounters,
6751 ) {
6752 doc_counters.merge(sheet_counters)
6753 }
6754
6755 #[no_mangle]
Servo_IsPropertyIdRecordedInUseCounter( use_counters: &UseCounters, id: nsCSSPropertyID, ) -> bool6756 pub unsafe extern "C" fn Servo_IsPropertyIdRecordedInUseCounter(
6757 use_counters: &UseCounters,
6758 id: nsCSSPropertyID,
6759 ) -> bool {
6760 let id = NonCustomPropertyId::from_nscsspropertyid(id).unwrap();
6761 use_counters.non_custom_properties.recorded(id)
6762 }
6763
6764 #[no_mangle]
Servo_IsUnknownPropertyRecordedInUseCounter( use_counters: &UseCounters, p: CountedUnknownProperty, ) -> bool6765 pub unsafe extern "C" fn Servo_IsUnknownPropertyRecordedInUseCounter(
6766 use_counters: &UseCounters,
6767 p: CountedUnknownProperty,
6768 ) -> bool {
6769 use_counters.counted_unknown_properties.recorded(p)
6770 }
6771
6772 #[no_mangle]
Servo_IsCssPropertyRecordedInUseCounter( use_counters: &UseCounters, property: &nsACString, known_prop: *mut bool, ) -> bool6773 pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
6774 use_counters: &UseCounters,
6775 property: &nsACString,
6776 known_prop: *mut bool,
6777 ) -> bool {
6778 *known_prop = false;
6779
6780 let prop_name = property.as_str_unchecked();
6781 if let Ok(p) = PropertyId::parse_unchecked_for_testing(prop_name) {
6782 if let Some(id) = p.non_custom_id() {
6783 *known_prop = true;
6784 return use_counters.non_custom_properties.recorded(id);
6785 }
6786 }
6787
6788 if let Some(p) = CountedUnknownProperty::parse_for_testing(prop_name) {
6789 *known_prop = true;
6790 return use_counters.counted_unknown_properties.recorded(p)
6791 }
6792
6793 false
6794 }
6795
6796 #[no_mangle]
Servo_SharedMemoryBuilder_Create( buffer: *mut u8, len: usize, ) -> *mut RawServoSharedMemoryBuilder6797 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Create(
6798 buffer: *mut u8,
6799 len: usize,
6800 ) -> *mut RawServoSharedMemoryBuilder {
6801 let mut builder = Box::new(SharedMemoryBuilder::new(buffer, len));
6802
6803 // We have Arc<UnparsedValue>s in style sheets due to CSS variables being
6804 // used in shorthand property declarations. There aren't many, though,
6805 // and they aren't big, so we just allow their duplication for now.
6806 builder.add_allowed_duplication_type::<UnparsedValue>();
6807
6808 Box::into_raw(builder) as *mut _
6809 }
6810
6811 #[no_mangle]
Servo_SharedMemoryBuilder_AddStylesheet( builder: &mut RawServoSharedMemoryBuilder, raw_contents: &RawServoStyleSheetContents, error_message: &mut nsACString, ) -> *const ServoCssRules6812 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_AddStylesheet(
6813 builder: &mut RawServoSharedMemoryBuilder,
6814 raw_contents: &RawServoStyleSheetContents,
6815 error_message: &mut nsACString,
6816 ) -> *const ServoCssRules {
6817 let builder = SharedMemoryBuilder::from_ffi_mut(builder);
6818 let contents = StylesheetContents::as_arc(&raw_contents);
6819
6820 // Assert some things we assume when we create a style sheet from shared
6821 // memory.
6822 debug_assert_eq!(contents.origin, Origin::UserAgent);
6823 debug_assert_eq!(contents.quirks_mode, QuirksMode::NoQuirks);
6824 debug_assert!(contents.source_map_url.read().is_none());
6825 debug_assert!(contents.source_url.read().is_none());
6826
6827 match builder.write(&contents.rules) {
6828 Ok(rules_ptr) => {
6829 (*rules_ptr).with_raw_offset_arc(|arc| *Locked::arc_as_borrowed(arc) as *const _)
6830 },
6831 Err(message) => {
6832 error_message.assign(&message);
6833 ptr::null()
6834 },
6835 }
6836 }
6837
6838 #[no_mangle]
Servo_SharedMemoryBuilder_GetLength( builder: &mut RawServoSharedMemoryBuilder, ) -> usize6839 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_GetLength(
6840 builder: &mut RawServoSharedMemoryBuilder,
6841 ) -> usize {
6842 let builder = SharedMemoryBuilder::from_ffi_mut(builder);
6843 builder.len()
6844 }
6845
6846 #[no_mangle]
Servo_SharedMemoryBuilder_Drop(builder: *mut RawServoSharedMemoryBuilder)6847 pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(builder: *mut RawServoSharedMemoryBuilder) {
6848 SharedMemoryBuilder::drop_ffi(builder)
6849 }
6850
6851 /// Returns a unique pointer to a clone of the shape image.
6852 ///
6853 /// Probably temporary, as we move more stuff to cbindgen.
6854 #[no_mangle]
6855 #[must_use]
Servo_CloneBasicShape( v: &computed::basic_shape::BasicShape, ) -> *mut computed::basic_shape::BasicShape6856 pub unsafe extern "C" fn Servo_CloneBasicShape(
6857 v: &computed::basic_shape::BasicShape,
6858 ) -> *mut computed::basic_shape::BasicShape {
6859 Box::into_raw(Box::new(v.clone()))
6860 }
6861
6862 #[no_mangle]
Servo_StyleArcSlice_EmptyPtr() -> *mut c_void6863 pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
6864 style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
6865 }
6866
6867 #[no_mangle]
Servo_LoadData_GetLazy( source: &url::LoadDataSource, ) -> *const url::LoadData6868 pub unsafe extern "C" fn Servo_LoadData_GetLazy(
6869 source: &url::LoadDataSource,
6870 ) -> *const url::LoadData {
6871 source.get()
6872 }
6873
6874 #[no_mangle]
Servo_LengthPercentage_ToCss( lp: &computed::LengthPercentage, result: &mut nsAString )6875 pub extern "C" fn Servo_LengthPercentage_ToCss(
6876 lp: &computed::LengthPercentage,
6877 result: &mut nsAString
6878 ) {
6879 lp.to_css(&mut CssWriter::new(result)).unwrap();
6880 }
6881
6882 #[no_mangle]
Servo_CursorKind_Parse( cursor: &nsACString, result: &mut computed::ui::CursorKind, ) -> bool6883 pub unsafe extern "C" fn Servo_CursorKind_Parse(
6884 cursor: &nsACString,
6885 result: &mut computed::ui::CursorKind,
6886 ) -> bool {
6887 match computed::ui::CursorKind::from_ident(cursor.as_str_unchecked()) {
6888 Ok(c) => {
6889 *result = c;
6890 true
6891 }
6892 Err(..) => false,
6893 }
6894 }
6895