Skip to content

Commit

Permalink
style: Parse sheets on the thread pool.
Browse files Browse the repository at this point in the history
Note that we also drop the dead optional aReusableSheets argument from
the async parsing path, since it was always null.

Bug: 1346988
Reviewed-by: bz,emilio
MozReview-Commit-ID: KddpGFdaqEe
  • Loading branch information
bholley authored and emilio committed Apr 28, 2018
1 parent c06e3dc commit dfa019c
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 21 deletions.
6 changes: 6 additions & 0 deletions components/style/gecko_bindings/sugar/refptr.rs
Expand Up @@ -312,3 +312,9 @@ impl_threadsafe_refcount!(
Gecko_AddRefSharedFontListArbitraryThread,
Gecko_ReleaseSharedFontListArbitraryThread
);

impl_threadsafe_refcount!(
::gecko_bindings::structs::SheetLoadDataHolder,
Gecko_AddRefSheetLoadDataHolderArbitraryThread,
Gecko_ReleaseSheetLoadDataHolderArbitraryThread
);
7 changes: 3 additions & 4 deletions components/style/stylesheets/import_rule.rs
Expand Up @@ -171,10 +171,9 @@ pub struct ImportRule {
/// The `<url>` this `@import` rule is loading.
pub url: CssUrl,

/// The stylesheet is always present.
///
/// It contains an empty list of rules and namespace set that is updated
/// when it loads.
/// The stylesheet is always present. However, in the case of gecko async
/// parsing, we don't actually have a Gecko sheet at first, and so the
/// ImportSheet just has stub behavior until it appears.
pub stylesheet: ImportSheet,

/// The line and column of the rule's source code.
Expand Down
68 changes: 58 additions & 10 deletions ports/geckolib/glue.rs
Expand Up @@ -6,6 +6,7 @@ use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation};
use cssparser::ToCss as ParserToCss;
use env_logger::Builder;
use malloc_size_of::MallocSizeOfOps;
use nsstring::nsCString;
use selectors::{NthIndexCache, SelectorList};
use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
Expand Down Expand Up @@ -92,7 +93,8 @@ use style::gecko_bindings::structs;
use style::gecko_bindings::structs::{CallerType, CSSPseudoElementType, CompositeOperation};
use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{RawServoStyleRule, ComputedStyleStrong, RustString};
use style::gecko_bindings::structs::{ServoStyleSheet, SheetLoadData, SheetParsingMode, nsAtom, nsCSSPropertyID};
use style::gecko_bindings::structs::{ServoStyleSheet, SheetLoadData, SheetLoadDataHolder};
use style::gecko_bindings::structs::{SheetParsingMode, nsAtom, nsCSSPropertyID};
use style::gecko_bindings::structs::{nsCSSFontDesc, nsCSSCounterDesc};
use style::gecko_bindings::structs::{nsRestyleHint, nsChangeHint, PropertyValuePair};
use style::gecko_bindings::structs::AtomArray;
Expand Down Expand Up @@ -145,6 +147,7 @@ use style::stylesheets::{DocumentRule, FontFaceRule, FontFeatureValuesRule, Impo
use style::stylesheets::{KeyframesRule, MediaRule, NamespaceRule, Origin, OriginSet, PageRule};
use style::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
use style::stylesheets::import_rule::ImportSheet;
use style::stylesheets::keyframes_rule::{Keyframe, KeyframeSelector, KeyframesStepValue};
use style::stylesheets::supports_rule::parse_condition_or_declaration;
use style::stylist::{add_size_of_ua_cache, AuthorStylesEnabled, RuleInclusion, Stylist};
Expand All @@ -163,7 +166,7 @@ use style::values::specified::gecko::{IntersectionObserverRootMargin, PixelOrPer
use style::values::specified::source_size_list::SourceSizeList;
use style_traits::{CssWriter, ParsingMode, StyleParseErrorKind, ToCss};
use super::error_reporter::ErrorReporter;
use super::stylesheet_loader::StylesheetLoader;
use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};

/*
* For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
Expand Down Expand Up @@ -1122,6 +1125,15 @@ pub extern "C" fn Servo_StyleSheet_Empty(mode: SheetParsingMode) -> RawServoStyl
).into_strong()
}

fn mode_to_origin(mode: SheetParsingMode) -> Origin {
match mode {
SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
SheetParsingMode::eUserSheetFeatures => Origin::User,
SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
}
}

/// Note: The load_data corresponds to this sheet, and is passed as the parent
/// load data for child sheet loads. It may be null for certain cases where we
/// know we won't have child loads.
Expand All @@ -1140,13 +1152,6 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(
let global_style_data = &*GLOBAL_STYLE_DATA;
let input: &str = unsafe { (*bytes).as_str_unchecked() };

let origin = match mode {
SheetParsingMode::eAuthorSheetFeatures => Origin::Author,
SheetParsingMode::eUserSheetFeatures => Origin::User,
SheetParsingMode::eAgentSheetFeatures => Origin::UserAgent,
SheetParsingMode::eSafeAgentSheetFeatures => Origin::UserAgent,
};

let reporter = ErrorReporter::new(stylesheet, loader, extra_data);
let url_data = unsafe { RefPtr::from_ptr_ref(&extra_data) };
let loader = if loader.is_null() {
Expand All @@ -1163,12 +1168,44 @@ pub extern "C" fn Servo_StyleSheet_FromUTF8Bytes(


Arc::new(StylesheetContents::from_str(
input, url_data.clone(), origin,
input, url_data.clone(), mode_to_origin(mode),
&global_style_data.shared_lock, loader, &reporter,
quirks_mode.into(), line_number_offset)
).into_strong()
}

#[no_mangle]
pub extern "C" fn Servo_StyleSheet_FromUTF8BytesAsync(
load_data: *mut SheetLoadDataHolder,
extra_data: *mut URLExtraData,
bytes: *const nsACString,
mode: SheetParsingMode,
line_number_offset: u32,
quirks_mode: nsCompatibility,
) {
let (load_data, extra_data, bytes) = unsafe {
let mut b = nsCString::new();
b.assign(&*bytes);
(RefPtr::new(load_data), RefPtr::new(extra_data), b)
};
let async_parser = AsyncStylesheetParser::new(
load_data,
extra_data,
bytes,
mode_to_origin(mode),
quirks_mode.into(),
line_number_offset
);

if let Some(thread_pool) = STYLE_THREAD_POOL.style_thread_pool.as_ref() {
thread_pool.spawn(|| {
async_parser.parse();
});
} else {
async_parser.parse();
}
}

#[no_mangle]
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(
raw_data: RawServoStyleSetBorrowed,
Expand Down Expand Up @@ -2051,6 +2088,17 @@ pub extern "C" fn Servo_ImportRule_GetSheet(
})
}

#[no_mangle]
pub extern "C" fn Servo_ImportRule_SetSheet(
rule: RawServoImportRuleBorrowed,
sheet: *mut ServoStyleSheet,
) {
write_locked_arc(rule, |rule: &mut ImportRule| {
let sheet = unsafe { GeckoStyleSheet::new(sheet) };
rule.stylesheet = ImportSheet::new(sheet);
})
}

#[no_mangle]
pub extern "C" fn Servo_Keyframe_GetKeyText(
keyframe: RawServoKeyframeBorrowed,
Expand Down
1 change: 1 addition & 0 deletions ports/geckolib/lib.rs
Expand Up @@ -9,6 +9,7 @@ extern crate env_logger;
extern crate libc;
#[macro_use] extern crate log;
extern crate malloc_size_of;
extern crate nsstring;
extern crate selectors;
extern crate servo_arc;
extern crate smallvec;
Expand Down
91 changes: 84 additions & 7 deletions ports/geckolib/stylesheet_loader.rs
Expand Up @@ -3,15 +3,24 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::SourceLocation;
use nsstring::nsCString;
use servo_arc::Arc;
use style::context::QuirksMode;
use style::error_reporting::NullReporter;
use style::gecko::data::GeckoStyleSheet;
use style::gecko::global_style_data::GLOBAL_STYLE_DATA;
use style::gecko_bindings::bindings;
use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
use style::gecko_bindings::structs::{Loader, ServoStyleSheet, SheetLoadData, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
use style::gecko_bindings::structs::{ServoStyleSheet, SheetLoadData, SheetLoadDataHolder};
use style::gecko_bindings::structs::URLExtraData;
use style::gecko_bindings::sugar::ownership::FFIArcHelpers;
use style::gecko_bindings::sugar::refptr::RefPtr;
use style::media_queries::MediaList;
use style::parser::ParserContext;
use style::shared_lock::{Locked, SharedRwLock};
use style::stylesheets::{ImportRule, StylesheetLoader as StyleStylesheetLoader};
use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader};
use style::stylesheets::StylesheetContents;
use style::stylesheets::import_rule::ImportSheet;
use style::values::CssUrl;

Expand Down Expand Up @@ -41,15 +50,11 @@ impl StyleStylesheetLoader for StylesheetLoader {
// so this raw pointer will still be valid.

let child_sheet = unsafe {
let (spec_bytes, spec_len) = url.as_slice_components();
let base_url_data = url.extra_data.get();
Gecko_LoadStyleSheet(self.0,
self.1,
self.2,
self.3,
base_url_data,
spec_bytes,
spec_len as u32,
url.for_ffi(),
media.into_strong())
};

Expand All @@ -60,3 +65,75 @@ impl StyleStylesheetLoader for StylesheetLoader {
Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet }))
}
}

pub struct AsyncStylesheetParser {
load_data: RefPtr<SheetLoadDataHolder>,
extra_data: RefPtr<URLExtraData>,
bytes: nsCString,
origin: Origin,
quirks_mode: QuirksMode,
line_number_offset: u32,
}

impl AsyncStylesheetParser {
pub fn new(
load_data: RefPtr<SheetLoadDataHolder>,
extra_data: RefPtr<URLExtraData>,
bytes: nsCString,
origin: Origin,
quirks_mode: QuirksMode,
line_number_offset: u32,
) -> Self {
AsyncStylesheetParser {
load_data,
extra_data,
bytes,
origin,
quirks_mode,
line_number_offset,
}
}

pub fn parse(self) {
let global_style_data = &*GLOBAL_STYLE_DATA;
let input: &str = unsafe { (*self.bytes).as_str_unchecked() };

// Note: Parallel CSS parsing doesn't report CSS errors. When errors
// are being logged, Gecko prevents the parallel parsing path from
// running.
let sheet = Arc::new(StylesheetContents::from_str(
input, self.extra_data.clone(), self.origin,
&global_style_data.shared_lock, Some(&self), &NullReporter,
self.quirks_mode.into(), self.line_number_offset)
);

unsafe {
bindings::Gecko_StyleSheet_FinishAsyncParse(self.load_data.get(), sheet.into_strong());
}
}
}

impl StyleStylesheetLoader for AsyncStylesheetParser {
fn request_stylesheet(
&self,
url: CssUrl,
source_location: SourceLocation,
_context: &ParserContext,
lock: &SharedRwLock,
media: Arc<Locked<MediaList>>,
) -> Arc<Locked<ImportRule>> {
let stylesheet = ImportSheet::new_pending(self.origin, self.quirks_mode);
let rule = Arc::new(lock.wrap(ImportRule { url: url.clone(), source_location, stylesheet }));

unsafe {
bindings::Gecko_LoadStyleSheetAsync(
self.load_data.get(),
url.for_ffi(),
media.into_strong(),
rule.clone().into_strong()
);
}

rule
}
}

0 comments on commit dfa019c

Please sign in to comment.