geckolib: Allow Servo_ComputeColor to report errors to the console. draft
authorCameron McCormack <cam@mcc.id.au>
Mon, 04 Dec 2017 12:53:13 +0800
changeset 706734 b3d2e7ef70d981cb4891337e1d8e5c7c2844a65d
parent 706733 5069a78d3b06b7d356eae78ece3117ff621b67b1
child 706735 175f1192678eac029c7dd70447c3449df25a85eb
push id91902
push userbmo:cam@mcc.id.au
push dateMon, 04 Dec 2017 05:26:25 +0000
milestone59.0a1
geckolib: Allow Servo_ComputeColor to report errors to the console. MozReview-Commit-ID: DgTKstk0RDd
servo/ports/geckolib/glue.rs
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::{Parser, ParserInput};
+use cssparser::{ParseErrorKind, Parser, ParserInput};
 use cssparser::ToCss as ParserToCss;
 use env_logger::LogBuilder;
 use malloc_size_of::MallocSizeOfOps;
 use selectors::{Element, NthIndexCache};
 use selectors::matching::{MatchingContext, MatchingMode, matches_selector};
 use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
 use std::cell::RefCell;
 use std::env;
@@ -17,17 +17,17 @@ use std::mem;
 use std::ptr;
 use style::applicable_declarations::ApplicableDeclarationBlock;
 use style::context::{CascadeInputs, QuirksMode, SharedStyleContext, StyleContext};
 use style::context::ThreadLocalStyleContext;
 use style::data::{ElementStyles, self};
 use style::dom::{ShowSubtreeData, TDocument, TElement, TNode};
 use style::driver;
 use style::element_state::{DocumentState, ElementState};
-use style::error_reporting::{NullReporter, ParseErrorReporter};
+use style::error_reporting::{ContextualParseError, NullReporter, ParseErrorReporter};
 use style::font_metrics::{FontMetricsProvider, get_metrics_provider_for_product};
 use style::gecko::data::{GeckoStyleSheet, PerDocumentStyleData, PerDocumentStyleDataImpl};
 use style::gecko::global_style_data::{GLOBAL_STYLE_DATA, GlobalStyleData, STYLE_THREAD_POOL};
 use style::gecko::restyle_damage::GeckoRestyleDamage;
 use style::gecko::selector_parser::PseudoElement;
 use style::gecko::traversal::RecalcStyleOnly;
 use style::gecko::wrapper::{GeckoElement, GeckoNode};
 use style::gecko_bindings::bindings;
@@ -145,17 +145,17 @@ use style::traversal::resolve_style;
 use style::traversal_flags::{self, TraversalFlags};
 use style::values::{CustomIdent, KeyframesName};
 use style::values::animated::{Animate, Procedure, ToAnimatedZero};
 use style::values::computed::{Context, ToComputedValue};
 use style::values::distance::ComputeSquaredDistance;
 use style::values::specified;
 use style::values::specified::gecko::IntersectionObserverRootMargin;
 use style::values::specified::source_size_list::SourceSizeList;
-use style_traits::{ParsingMode, ToCss};
+use style_traits::{ParsingMode, StyleParseErrorKind, ToCss};
 use super::error_reporter::ErrorReporter;
 use super::stylesheet_loader::StylesheetLoader;
 
 /*
  * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in
  * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against
  * those signatures as well, giving us a second declaration of all the Servo_* functions in this
  * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to
@@ -4544,45 +4544,72 @@ pub unsafe extern "C" fn Servo_SelectorL
     Box::into_raw(Box::new(selector_list)) as *mut RawServoSelectorList
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_SelectorList_Drop(list: RawServoSelectorListOwned) {
     let _ = list.into_box::<::selectors::SelectorList<SelectorImpl>>();
 }
 
-fn parse_color(value: &str) -> Result<specified::Color, ()> {
+fn parse_color(
+    value: &str,
+    error_reporter: Option<&ErrorReporter>,
+) -> Result<specified::Color, ()> {
     let mut input = ParserInput::new(value);
     let mut parser = Parser::new(&mut input);
-    parser.parse_entirely(specified::Color::parse_color).map_err(|_| ())
+    let start_position = parser.position();
+    parser.parse_entirely(specified::Color::parse_color).map_err(|err| {
+        if let Some(error_reporter) = error_reporter {
+            match err.kind {
+                ParseErrorKind::Custom(StyleParseErrorKind::ValueError(..)) => {
+                    let location = err.location.clone();
+                    let error = ContextualParseError::UnsupportedValue(
+                        parser.slice_from(start_position),
+                        err,
+                    );
+                    error_reporter.report(location, error);
+                }
+                // Ignore other kinds of errors that might be reported, such as
+                // ParseErrorKind::Basic(BasicParseErrorKind::UnexpectedToken),
+                // since Gecko doesn't report those to the error console.
+                _ => {}
+            }
+        }
+    })
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_IsValidCSSColor(
     value: *const nsAString,
 ) -> bool {
     let value = unsafe { (*value).to_string() };
-    parse_color(&value).is_ok()
+    parse_color(&value, None).is_ok()
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputeColor(
     raw_data: RawServoStyleSetBorrowedOrNull,
     current_color: structs::nscolor,
     value: *const nsAString,
     result_color: *mut structs::nscolor,
     was_current_color: *mut bool,
+    loader: *mut Loader,
 ) -> bool {
     use style::gecko;
 
     let current_color = gecko::values::convert_nscolor_to_rgba(current_color);
     let value = unsafe { (*value).to_string() };
     let result_color = unsafe { result_color.as_mut().unwrap() };
 
-    match parse_color(&value) {
+    let reporter = unsafe { loader.as_mut() }.map(|loader| {
+        // Make an ErrorReporter that will report errors as being "from DOM".
+        ErrorReporter::new(ptr::null_mut(), loader, ptr::null_mut())
+    });
+
+    match parse_color(&value, reporter.as_ref()) {
         Ok(specified_color) => {
             let computed_color = match raw_data {
                 Some(raw_data) => {
                     let data = PerDocumentStyleData::from_ffi(raw_data).borrow();
                     let metrics = get_metrics_provider_for_product();
                     let mut conditions = Default::default();
                     let context = create_context(
                         &data,