Bug 1365045 - Introduce ValueInBooleanContext in nsCSSKTableEntry and use it in the boolean context. r?heycam draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Mon, 23 Jul 2018 07:27:07 +0900
changeset 821306 45969a48e4c2b78a4a9f7f23a15a2ead838855d9
parent 821277 a10e41860e7d2e0c92b2f8adc09d297378593d26
child 821307 0c5d1c8a21ea2cb10b0a268211dff3a6f242c68e
push id117059
push userbmo:hikezoe@mozilla.com
push dateSun, 22 Jul 2018 22:27:45 +0000
reviewersheycam
bugs1365045
milestone63.0a1
Bug 1365045 - Introduce ValueInBooleanContext in nsCSSKTableEntry and use it in the boolean context. r?heycam The values in the boolean context depend on its feature. For examples, in the case of prefers-reduced-motion 'no-preference' means false and 'reduced' mean true in the boolean context, whereas in the case of prefers-contrast 'no-preference' means false and other two values, 'high' and 'low' means true in the boolean context. To support it we introduce a new enum into each nsCSSKTableEntry to represent the value in the boolean context and use it when we have no specified value in the media feature (i.e. in the boolean context). MozReview-Commit-ID: Kr30bA1MtKx
layout/style/ServoBindings.toml
layout/style/nsCSSProps.h
servo/components/style/gecko/media_queries.rs
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -130,16 +130,17 @@ rusty-enums = [
     "nsStyleUnit",
     "nsCSSKeyword",
     "nsIDocument_DocumentTheme",
     "nsIDocument_Type",
     "nsCSSUnit",
     "nsCSSFontDesc",
     "nsCSSPropertyID",
     "nsCSSCounterDesc",
+    "nsCSSKTableEntry_ValueInBooleanContext",
     "nsMediaFeature_RangeType",
     "nsMediaFeature_ValueType",
     "nsresult",
     "nsAtom_AtomKind",
     "nsStyleImageLayers_LayerType",
     "nsTimingFunction_Type",
     "mozilla::ServoElementSnapshotFlags",
     "mozilla::Side",
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -35,42 +35,54 @@ class ComputedStyle;
 
 extern "C" {
   nsCSSPropertyID Servo_ResolveLogicalProperty(nsCSSPropertyID,
                                                const mozilla::ComputedStyle*);
 }
 
 struct nsCSSKTableEntry
 {
+  // Indicates what this value represents in the boolean context.
+  enum ValueInBooleanContext {
+    eFalse,
+    eTrue,
+  };
+
   // nsCSSKTableEntry objects can be initialized either with an int16_t value
   // or a value of an enumeration type that can fit within an int16_t.
 
   constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, int16_t aValue)
     : mKeyword(aKeyword)
     , mValue(aValue)
+    , mValueInBooleanContext(ValueInBooleanContext::eTrue)
   {
   }
 
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
-  constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword, T aValue)
+  constexpr nsCSSKTableEntry(nsCSSKeyword aKeyword,
+                             T aValue,
+                             ValueInBooleanContext aValueInBooleanContext =
+                               eTrue)
     : mKeyword(aKeyword)
     , mValue(static_cast<int16_t>(aValue))
+    , mValueInBooleanContext(aValueInBooleanContext)
   {
     static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                   "aValue must be an enum that fits within mValue");
   }
 
   bool IsSentinel() const
   {
     return mKeyword == eCSSKeyword_UNKNOWN && mValue == -1;
   }
 
   nsCSSKeyword mKeyword;
   int16_t mValue;
+  ValueInBooleanContext mValueInBooleanContext;
 };
 
 class nsCSSProps {
 public:
   typedef mozilla::CSSEnabledState EnabledState;
   typedef mozilla::CSSPropFlags Flags;
   typedef nsCSSKTableEntry KTableEntry;
 
--- a/servo/components/style/gecko/media_queries.rs
+++ b/servo/components/style/gecko/media_queries.rs
@@ -8,17 +8,18 @@ use app_units::AU_PER_PX;
 use app_units::Au;
 use context::QuirksMode;
 use cssparser::{Parser, RGBA, Token};
 use euclid::Size2D;
 use euclid::TypedScale;
 use gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
 use gecko_bindings::bindings;
 use gecko_bindings::structs;
-use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKeyword, nsCSSUnit, nsCSSValue};
+use gecko_bindings::structs::{nsCSSKTableEntry, nsCSSKTableEntry_ValueInBooleanContext};
+use gecko_bindings::structs::{nsCSSKeyword, nsCSSUnit, nsCSSValue};
 use gecko_bindings::structs::{nsMediaFeature, nsMediaFeature_RangeType};
 use gecko_bindings::structs::{nsMediaFeature_ValueType, nsPresContext};
 use gecko_bindings::structs::RawGeckoPresContextOwned;
 use media_queries::MediaType;
 use parser::{Parse, ParserContext};
 use properties::ComputedValues;
 use servo_arc::Arc;
 use std::fmt::{self, Write};
@@ -459,17 +460,17 @@ impl MediaExpressionValue {
             MediaExpressionValue::Enumerated(value) => unsafe {
                 use std::{slice, str};
                 use std::os::raw::c_char;
 
                 // NB: All the keywords on nsMediaFeatures are static,
                 // well-formed utf-8.
                 let mut length = 0;
 
-                let (keyword, _value) = find_in_table(
+                let (keyword, _value, _) = find_in_table(
                     *for_expr.feature.mData.mKeywordTable.as_ref(),
                     |_kw, val| val == value,
                 ).expect("Value not found in the keyword table?");
 
                 let buffer: *const c_char = bindings::Gecko_CSSKeywordString(keyword, &mut length);
                 let buffer = slice::from_raw_parts(buffer as *const u8, length as usize);
 
                 let string = str::from_utf8_unchecked(buffer);
@@ -494,30 +495,30 @@ where
         }
     }
     None
 }
 
 unsafe fn find_in_table<F>(
     mut current_entry: *const nsCSSKTableEntry,
     mut f: F,
-) -> Option<(nsCSSKeyword, i16)>
+) -> Option<(nsCSSKeyword, i16, nsCSSKTableEntry_ValueInBooleanContext)>
 where
     F: FnMut(nsCSSKeyword, i16) -> bool,
 {
     loop {
         let value = (*current_entry).mValue;
         let keyword = (*current_entry).mKeyword;
 
         if value == -1 {
             return None; // End of the table.
         }
 
         if f(keyword, value) {
-            return Some((keyword, value));
+            return Some((keyword, value, (*current_entry).mValueInBooleanContext));
         }
 
         current_entry = current_entry.offset(1);
     }
 }
 
 fn parse_feature_value<'i, 't>(
     feature: &nsMediaFeature,
@@ -561,17 +562,17 @@ fn parse_feature_value<'i, 't>(
             let keyword = unsafe {
                 bindings::Gecko_LookupCSSKeyword(keyword.as_bytes().as_ptr(), keyword.len() as u32)
             };
 
             let first_table_entry: *const nsCSSKTableEntry =
                 unsafe { *feature.mData.mKeywordTable.as_ref() };
 
             let value = match unsafe { find_in_table(first_table_entry, |kw, _| kw == keyword) } {
-                Some((_kw, value)) => value,
+                Some((_kw, value, _)) => value,
                 None => {
                     return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
                 },
             };
 
             MediaExpressionValue::Enumerated(value)
         },
         nsMediaFeature_ValueType::eIdent => {
@@ -829,16 +830,24 @@ impl MediaFeatureExpression {
                 return match *actual_value {
                     BoolInteger(v) => v,
                     Integer(v) => v != 0,
                     Length(ref l) => computed::Context::for_media_query_evaluation(
                         device,
                         quirks_mode,
                         |context| l.to_computed_value(&context).px() != 0.,
                     ),
+                    Enumerated(value) =>  {
+                        let (_kw, _value, value_in_boolean_context) = unsafe { find_in_table(
+                                *self.feature.mData.mKeywordTable.as_ref(),
+                                |_kw, val| val == value,
+                            ).expect("Value not found in the keyword table?")
+                        };
+                        value_in_boolean_context == nsCSSKTableEntry_ValueInBooleanContext::eTrue
+                    }
                     _ => true,
                 };
             },
         };
 
         // FIXME(emilio): Handle the possible floating point errors?
         let cmp = match (actual_value, required_value) {
             (&Length(ref one), &Length(ref other)) => {