Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Csoregi Natalia 2018-02-01 20:14:53 +02:00
commit 486051b718
58 changed files with 1031 additions and 948 deletions

View File

@ -50,7 +50,8 @@ tabbrowser {
/* Needed to allow tabs to shrink to be skinnier than their page-title: */
min-width: 0;
}
.scrollbox-innerbox {
.tabbrowser-arrowscrollbox > .arrowscrollbox-scrollbox > .scrollbox-innerbox {
/* Needed to prevent tabstrip from growing as wide as the sum of the tabs'
page-title widths (when we'd rather have it be as wide as the window and
compress the tabs to their minimum size): */

View File

@ -1478,7 +1478,6 @@ nsIDocument::nsIDocument()
mHasDisplayDocument(false),
mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mPostedFlushUserFontSet(false),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false),
@ -3993,8 +3992,11 @@ nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
UpdateFrameRequestCallbackSchedulingState();
// Now that we have a shell, we might have @font-face rules.
RebuildUserFontSet();
// Now that we have a shell, we might have @font-face rules (the presence of a
// shell may change which rules apply to us). We don't need to do anything
// like EnsureStyleFlush or such, there's nothing to update yet and when stuff
// is ready to update we'll flush the font set.
MarkUserFontSetDirty();
return shell.forget();
}
@ -4090,8 +4092,10 @@ nsDocument::DeleteShell()
ImageTracker()->RequestDiscardAll();
// Now that we no longer have a shell, we need to forget about any FontFace
// objects for @font-face rules that came from the style set.
RebuildUserFontSet();
// objects for @font-face rules that came from the style set. There's no need
// to call EnsureStyleFlush either, the shell is going away anyway, so there's
// no point on it.
MarkUserFontSetDirty();
nsIPresShell* oldShell = mPresShell;
mPresShell = nullptr;
@ -12668,7 +12672,7 @@ nsIDocument::GetUserFontSet(bool aFlushUserFontSet)
// we *never* build the user font set until the first call to
// GetUserFontSet. However, once it's been requested, we can't wait
// for somebody to call GetUserFontSet in order to rebuild it (see
// comments below in RebuildUserFontSet for why).
// comments below in MarkUserFontSetDirty for why).
#ifdef DEBUG
bool userFontSetGottenBefore = mGetUserFontSetCalled;
#endif
@ -12705,42 +12709,44 @@ nsIDocument::FlushUserFontSet()
// does we'll create it.
}
if (mFontFaceSetDirty) {
if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
nsTArray<nsFontFaceRuleContainer> rules;
nsIPresShell* shell = GetShell();
if (shell && !shell->StyleSet()->AppendFontFaceRules(rules)) {
return;
}
if (!mFontFaceSetDirty) {
return;
}
bool changed = false;
mFontFaceSetDirty = false;
if (!mFontFaceSet && !rules.IsEmpty()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this);
}
if (mFontFaceSet) {
changed = mFontFaceSet->UpdateRules(rules);
}
// We need to enqueue a style change reflow (for later) to
// reflect that we're modifying @font-face rules. (However,
// without a reflow, nothing will happen to start any downloads
// that are needed.)
if (changed && shell) {
nsPresContext* presContext = shell->GetPresContext();
if (presContext) {
presContext->UserFontSetUpdated();
}
}
if (gfxPlatform::GetPlatform()->DownloadableFontsEnabled()) {
nsTArray<nsFontFaceRuleContainer> rules;
nsIPresShell* shell = GetShell();
if (shell && !shell->StyleSet()->AppendFontFaceRules(rules)) {
return;
}
mFontFaceSetDirty = false;
if (!mFontFaceSet && !rules.IsEmpty()) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this);
}
bool changed = false;
if (mFontFaceSet) {
changed = mFontFaceSet->UpdateRules(rules);
}
// We need to enqueue a style change reflow (for later) to
// reflect that we're modifying @font-face rules. (However,
// without a reflow, nothing will happen to start any downloads
// that are needed.)
if (changed && shell) {
if (nsPresContext* presContext = shell->GetPresContext()) {
presContext->UserFontSetUpdated();
}
}
}
}
void
nsIDocument::RebuildUserFontSet()
nsIDocument::MarkUserFontSetDirty()
{
if (!mGetUserFontSetCalled) {
// We want to lazily build the user font set the first time it's
@ -12750,27 +12756,6 @@ nsIDocument::RebuildUserFontSet()
}
mFontFaceSetDirty = true;
if (nsIPresShell* shell = GetShell()) {
shell->SetNeedStyleFlush();
}
// Somebody has already asked for the user font set, so we need to
// post an event to rebuild it. Setting the user font set to be dirty
// and lazily rebuilding it isn't sufficient, since it is only the act
// of rebuilding it that will trigger the style change reflow that
// calls GetUserFontSet. (This reflow causes rebuilding of text runs,
// which starts font loads, whose completion causes another style
// change reflow).
if (!mPostedFlushUserFontSet) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsCOMPtr<nsIRunnable> ev =
NewRunnableMethod("nsIDocument::HandleRebuildUserFontSet",
this,
&nsIDocument::HandleRebuildUserFontSet);
if (NS_SUCCEEDED(Dispatch(TaskCategory::Other, ev.forget()))) {
mPostedFlushUserFontSet = true;
}
}
}
FontFaceSet*

View File

@ -3071,7 +3071,7 @@ public:
gfxUserFontSet* GetUserFontSet(bool aFlushUserFontSet = true);
void FlushUserFontSet();
void RebuildUserFontSet(); // asynchronously
void MarkUserFontSetDirty();
mozilla::dom::FontFaceSet* GetFonts() { return mFontFaceSet; }
// FontFaceSource
@ -3289,11 +3289,6 @@ protected:
mozilla::dom::XPathEvaluator* XPathEvaluator();
void HandleRebuildUserFontSet() {
mPostedFlushUserFontSet = false;
FlushUserFontSet();
}
// Update our frame request callback scheduling state, if needed. This will
// schedule or unschedule them, if necessary, and update
// mFrameRequestCallbacksScheduled. aOldShell should only be passed when
@ -3543,9 +3538,6 @@ protected:
// Has GetUserFontSet() been called?
bool mGetUserFontSetCalled : 1;
// Do we currently have an event posted to call FlushUserFontSet?
bool mPostedFlushUserFontSet : 1;
// True if we have fired the DOMContentLoaded event, or don't plan to fire one
// (e.g. we're not being parsed at all).
bool mDidFireDOMContentLoaded : 1;

View File

@ -484,7 +484,7 @@ UnscaledFontFontconfig::GetWRFontDescriptor(WRFontDescriptorOutput aCb, void* aB
const char* path = mFile.c_str();
size_t pathLength = strlen(path);
aCb(reinterpret_cast<const uint8_t*>(path), pathLength, 0, aBaton);
aCb(reinterpret_cast<const uint8_t*>(path), pathLength, mIndex, aBaton);
return true;
}

View File

@ -71,7 +71,7 @@ UnscaledFontFreeType::GetFontDescriptor(FontDescriptorOutput aCb, void* aBaton)
const char* path = mFile.c_str();
size_t pathLength = strlen(path) + 1;
aCb(reinterpret_cast<const uint8_t*>(path), pathLength, 0, aBaton);
aCb(reinterpret_cast<const uint8_t*>(path), pathLength, mIndex, aBaton);
return true;
}

View File

@ -41,7 +41,7 @@ namespace gl {
#define GL_CONTEXT_PROVIDER_DEFAULT GLContextProviderCGL
#endif
#if defined(MOZ_X11)
#if defined(MOZ_X11) && !defined(MOZ_WAYLAND)
#define GL_CONTEXT_PROVIDER_NAME GLContextProviderGLX
#include "GLContextProviderImpl.h"
#undef GL_CONTEXT_PROVIDER_NAME

View File

@ -13,7 +13,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'uikit':
gl_provider = 'EAGL'
elif 'gtk' in CONFIG['MOZ_WIDGET_TOOLKIT']:
if CONFIG['MOZ_EGL_XRENDER_COMPOSITE']:
if CONFIG['MOZ_EGL_XRENDER_COMPOSITE'] or CONFIG['MOZ_WAYLAND']:
gl_provider = 'EGL'
else:
gl_provider = 'GLX'

View File

@ -40,6 +40,7 @@
#include "nsPresContext.h"
#include "nsIContent.h"
#include "nsIContentIterator.h"
#include "nsIPresShellInlines.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Event.h" // for Event::GetEventPopupControlState()
#include "mozilla/dom/PointerEventHandler.h"
@ -4595,11 +4596,12 @@ nsIPresShell::RestyleForCSSRuleChanges()
return;
}
mDocument->RebuildUserFontSet();
EnsureStyleFlush();
mDocument->MarkUserFontSetDirty();
if (mPresContext) {
mPresContext->RebuildCounterStyles();
mPresContext->RebuildFontFeatureValues();
mPresContext->MarkCounterStylesDirty();
mPresContext->MarkFontFeatureValuesDirty();
}
if (!mDidInitialize) {

View File

@ -314,9 +314,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType)
mUsesExChUnits(false),
mPendingViewportChange(false),
mCounterStylesDirty(true),
mPostedFlushCounterStyles(false),
mFontFeatureValuesDirty(true),
mPostedFlushFontFeatureValues(false),
mSuppressResizeReflow(false),
mIsVisual(false),
mFireAfterPaintEvents(false),
@ -2078,9 +2076,16 @@ nsPresContext::RebuildAllStyleData(nsChangeHint aExtraHint,
MOZ_CRASH("old style system disabled");
#endif
}
mDocument->RebuildUserFontSet();
RebuildCounterStyles();
RebuildFontFeatureValues();
// TODO(emilio): It's unclear to me why would these three calls below be
// needed. In particular, RebuildAllStyleData doesn't rebuild rules or
// specified style information and such (note the comment in
// ServoRestyleManager::RebuildAllStyleData re. the funny semantics), so I
// don't know why should we rebuild the user font set / counter styles /
// etc...
mDocument->MarkUserFontSetDirty();
MarkCounterStylesDirty();
MarkFontFeatureValuesDirty();
RestyleManager()->RebuildAllStyleData(aExtraHint, aRestyleHint);
}
@ -2426,27 +2431,14 @@ nsPresContext::FlushCounterStyles()
}
void
nsPresContext::RebuildCounterStyles()
nsPresContext::MarkCounterStylesDirty()
{
if (mCounterStyleManager->IsInitial()) {
// Still in its initial state, no need to reset.
// Still in its initial state, no need to touch anything.
return;
}
mCounterStylesDirty = true;
if (mShell) {
mShell->SetNeedStyleFlush();
}
if (!mPostedFlushCounterStyles) {
nsCOMPtr<nsIRunnable> ev =
NewRunnableMethod("nsPresContext::HandleRebuildCounterStyles",
this, &nsPresContext::HandleRebuildCounterStyles);
nsresult rv =
Document()->Dispatch(TaskCategory::Other, ev.forget());
if (NS_SUCCEEDED(rv)) {
mPostedFlushCounterStyles = true;
}
}
}
void
@ -3189,28 +3181,6 @@ nsPresContext::FlushFontFeatureValues()
}
}
void
nsPresContext::RebuildFontFeatureValues()
{
if (!mShell) {
return; // we've been torn down
}
mFontFeatureValuesDirty = true;
mShell->SetNeedStyleFlush();
if (!mPostedFlushFontFeatureValues) {
nsCOMPtr<nsIRunnable> ev =
NewRunnableMethod("nsPresContext::HandleRebuildFontFeatureValues",
this, &nsPresContext::HandleRebuildFontFeatureValues);
nsresult rv =
Document()->Dispatch(TaskCategory::Other, ev.forget());
if (NS_SUCCEEDED(rv)) {
mPostedFlushFontFeatureValues = true;
}
}
}
nsRootPresContext::nsRootPresContext(nsIDocument* aDocument,
nsPresContextType aType)
: nsPresContext(aDocument, aType)

View File

@ -998,7 +998,7 @@ public:
// as that value may be out of date when mPaintFlashingInitialized is false.
bool GetPaintFlashing() const;
bool SuppressingResizeReflow() const { return mSuppressResizeReflow; }
bool SuppressingResizeReflow() const { return mSuppressResizeReflow; }
gfxUserFontSet* GetUserFontSet(bool aFlushUserFontSet = true);
@ -1011,10 +1011,13 @@ public:
void NotifyMissingFonts();
void FlushCounterStyles();
void RebuildCounterStyles(); // asynchronously
void MarkCounterStylesDirty();
void FlushFontFeatureValues();
void RebuildFontFeatureValues(); // asynchronously
void MarkFontFeatureValuesDirty()
{
mFontFeatureValuesDirty = true;
}
// Ensure that it is safe to hand out CSS rules outside the layout
// engine by ensuring that all CSS style sheets have unique inners
@ -1265,16 +1268,6 @@ protected:
void AppUnitsPerDevPixelChanged();
void HandleRebuildCounterStyles() {
mPostedFlushCounterStyles = false;
FlushCounterStyles();
}
void HandleRebuildFontFeatureValues() {
mPostedFlushFontFeatureValues = false;
FlushFontFeatureValues();
}
bool HavePendingInputEvent();
// Can't be inline because we can't include nsStyleSet.h.
@ -1478,13 +1471,9 @@ protected:
// Is the current mCounterStyleManager valid?
unsigned mCounterStylesDirty : 1;
// Do we currently have an event posted to call FlushCounterStyles?
unsigned mPostedFlushCounterStyles: 1;
// Is the current mFontFeatureValuesLookup valid?
unsigned mFontFeatureValuesDirty : 1;
// Do we currently have an event posted to call FlushFontFeatureValues?
unsigned mPostedFlushFontFeatureValues: 1;
// resize reflow is suppressed when the only change has been to zoom
// the document rather than to change the document's dimensions

View File

@ -40,6 +40,7 @@
#include "nsILoadContext.h"
#include "nsINetworkPredictor.h"
#include "nsIPresShell.h"
#include "nsIPresShellInlines.h"
#include "nsIPrincipal.h"
#include "nsISupportsPriority.h"
#include "nsIWebNavigation.h"
@ -509,7 +510,7 @@ FontFaceSet::Add(FontFace& aFontFace, ErrorResult& aRv)
aFontFace.Status() == FontFaceLoadStatus::Loading;
mNonRuleFacesDirty = true;
RebuildUserFontSet();
MarkUserFontSetDirty();
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
return this;
@ -531,7 +532,7 @@ FontFaceSet::Clear()
mNonRuleFaces.Clear();
mNonRuleFacesDirty = true;
RebuildUserFontSet();
MarkUserFontSetDirty();
mHasLoadingFontFacesIsDirty = true;
CheckLoadingFinished();
}
@ -560,7 +561,7 @@ FontFaceSet::Delete(FontFace& aFontFace)
aFontFace.RemoveFontFaceSet(this);
mNonRuleFacesDirty = true;
RebuildUserFontSet();
MarkUserFontSetDirty();
mHasLoadingFontFacesIsDirty = true;
CheckLoadingFinished();
return true;
@ -1841,10 +1842,16 @@ FontFaceSet::FlushUserFontSet()
}
void
FontFaceSet::RebuildUserFontSet()
FontFaceSet::MarkUserFontSetDirty()
{
if (mDocument) {
mDocument->RebuildUserFontSet();
// Ensure we trigger at least a style flush, that will eventually flush the
// user font set. Otherwise the font loads that that flush may cause could
// never be triggered.
if (nsIPresShell* shell = mDocument->GetShell()) {
shell->EnsureStyleFlush();
}
mDocument->MarkUserFontSetDirty();
}
}
@ -1985,7 +1992,7 @@ FontFaceSet::UserFontSet::DoRebuildUserFontSet()
if (!mFontFaceSet) {
return;
}
mFontFaceSet->RebuildUserFontSet();
mFontFaceSet->MarkUserFontSetDirty();
}
/* virtual */ already_AddRefed<gfxUserFontEntry>

View File

@ -293,7 +293,7 @@ private:
const char* aMessage,
uint32_t aFlags,
nsresult aStatus);
void RebuildUserFontSet();
void MarkUserFontSetDirty();
void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
nsTArray<FontFaceRecord>& aOldRecords,

View File

@ -380,15 +380,11 @@ nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures
AppendFontTagAsString(feat.mTag, aResult);
// output value, if necessary
if (feat.mValue == 0) {
// 0 ==> off
aResult.AppendLiteral(" off");
} else if (feat.mValue > 1) {
// omit value if it's 1, implied by default
if (feat.mValue != 1) {
aResult.Append(' ');
aResult.AppendInt(feat.mValue);
}
// else, omit value if 1, implied by default
}
}

View File

@ -686,6 +686,13 @@
]
}
},
"tl": {
"default": {
"visibleDefaultEngines": [
"google", "yahoo", "bing", "amazondotcom", "ddg", "twitter"
]
}
},
"tr": {
"default": {
"visibleDefaultEngines": [

View File

@ -9,7 +9,7 @@
#![deny(missing_docs)]
#[cfg(feature = "gecko")]
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::{font_stretch, font_style, font_weight};
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{SourceLocation, CowRcStr};
use error_reporting::{ContextualParseError, ParseErrorReporter};
@ -25,6 +25,8 @@ use str::CssStringWriter;
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
use style_traits::{StyleParseErrorKind, ToCss};
use values::computed::font::FamilyName;
#[cfg(feature = "gecko")]
use values::specified::font::SpecifiedFontFeatureSettings;
use values::specified::url::SpecifiedUrl;
/// A source for a font-face rule.
@ -67,13 +69,17 @@ impl ToCss for UrlSource {
/// A font-display value for a @font-face rule.
/// The font-display descriptor determines how a font face is displayed based
/// on whether and when it is downloaded and ready to use.
define_css_keyword_enum!(FontDisplay:
"auto" => Auto,
"block" => Block,
"swap" => Swap,
"fallback" => Fallback,
"optional" => Optional);
add_impls_for_keyword_enum!(FontDisplay);
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum FontDisplay {
Auto,
Block,
Swap,
Fallback,
Optional,
}
/// A font-weight value for a @font-face rule.
/// The font-weight CSS property specifies the weight or boldness of the font.
@ -395,8 +401,8 @@ font_face_descriptors! {
],
/// The feature settings of this font face.
"font-feature-settings" feature_settings / mFontFeatureSettings: font_feature_settings::T = {
font_feature_settings::T::Normal
"font-feature-settings" feature_settings / mFontFeatureSettings: SpecifiedFontFeatureSettings = {
font_feature_settings::SpecifiedValue::normal()
},
/// The language override of this font face.

View File

@ -707,9 +707,9 @@ pub mod basic_shape {
}
StyleBasicShapeType::Polygon => {
let fill_rule = if other.mFillRule == StyleFillRule::Evenodd {
FillRule::EvenOdd
FillRule::Evenodd
} else {
FillRule::NonZero
FillRule::Nonzero
};
let mut coords = Vec::with_capacity(other.mCoordinates.len() / 2);
for i in 0..(other.mCoordinates.len() / 2) {

View File

@ -5,7 +5,7 @@
//! Bindings for CSS Rule objects
use byteorder::{BigEndian, WriteBytesExt};
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::{font_stretch, font_style, font_weight};
use counter_style;
use cssparser::UnicodeRange;
use font_face::{FontFaceRuleData, Source, FontDisplay, FontWeight};
@ -21,7 +21,7 @@ use std::fmt::{self, Write};
use std::str;
use str::CssStringWriter;
use values::computed::font::FamilyName;
use values::generics::FontSettings;
use values::specified::font::SpecifiedFontFeatureSettings;
/// A @font-face rule
pub type FontFaceRule = RefPtr<nsCSSFontFaceRule>;
@ -50,24 +50,24 @@ impl ToNsCssValue for FontWeight {
}
}
impl ToNsCssValue for font_feature_settings::T {
impl ToNsCssValue for SpecifiedFontFeatureSettings {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match self {
FontSettings::Normal => nscssvalue.set_normal(),
FontSettings::Tag(tags) => {
nscssvalue.set_pair_list(tags.into_iter().map(|entry| {
let mut feature = nsCSSValue::null();
let mut raw = [0u8; 4];
(&mut raw[..]).write_u32::<BigEndian>(entry.tag).unwrap();
feature.set_string(str::from_utf8(&raw).unwrap());
let mut index = nsCSSValue::null();
index.set_integer(entry.value.0 as i32);
(feature, index)
}))
}
if self.0.is_empty() {
nscssvalue.set_normal();
return;
}
nscssvalue.set_pair_list(self.0.into_iter().map(|entry| {
let mut feature = nsCSSValue::null();
let mut raw = [0u8; 4];
(&mut raw[..]).write_u32::<BigEndian>(entry.tag.0).unwrap();
feature.set_string(str::from_utf8(&raw).unwrap());
let mut index = nsCSSValue::null();
index.set_integer(entry.value.value());
(feature, index)
}))
}
}

View File

@ -348,10 +348,10 @@ impl GeckoStyleCoordConvertible for ExtremumLength {
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
coord.set_value(CoordDataValue::Enumerated(
match *self {
ExtremumLength::MaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
ExtremumLength::MinContent => NS_STYLE_WIDTH_MIN_CONTENT,
ExtremumLength::FitContent => NS_STYLE_WIDTH_FIT_CONTENT,
ExtremumLength::FillAvailable => NS_STYLE_WIDTH_AVAILABLE,
ExtremumLength::MozMaxContent => NS_STYLE_WIDTH_MAX_CONTENT,
ExtremumLength::MozMinContent => NS_STYLE_WIDTH_MIN_CONTENT,
ExtremumLength::MozFitContent => NS_STYLE_WIDTH_FIT_CONTENT,
ExtremumLength::MozAvailable => NS_STYLE_WIDTH_AVAILABLE,
}
))
}
@ -361,12 +361,12 @@ impl GeckoStyleCoordConvertible for ExtremumLength {
use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT};
match coord.as_value() {
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) =>
Some(ExtremumLength::MaxContent),
Some(ExtremumLength::MozMaxContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) =>
Some(ExtremumLength::MinContent),
Some(ExtremumLength::MozMinContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) =>
Some(ExtremumLength::FitContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => Some(ExtremumLength::FillAvailable),
Some(ExtremumLength::MozFitContent),
CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => Some(ExtremumLength::MozAvailable),
_ => None,
}
}

View File

@ -25,8 +25,6 @@
#![deny(missing_docs)]
#![recursion_limit = "500"] // For define_css_keyword_enum! in -moz-appearance
extern crate app_units;
extern crate arrayvec;
extern crate atomic_refcell;
@ -72,7 +70,6 @@ extern crate smallbitvec;
extern crate smallvec;
#[macro_use]
extern crate style_derive;
#[macro_use]
extern crate style_traits;
extern crate time;
extern crate uluru;

View File

@ -65,67 +65,6 @@ macro_rules! try_match_ident_ignore_ascii_case {
}}
}
macro_rules! define_numbered_css_keyword_enum {
($name: ident: $( $css: expr => $variant: ident = $value: expr ),+,) => {
define_numbered_css_keyword_enum!($name: $( $css => $variant = $value ),+);
};
($name: ident: $( $css: expr => $variant: ident = $value: expr ),+) => {
#[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub enum $name {
$( $variant = $value ),+
}
impl $crate::parser::Parse for $name {
fn parse<'i, 't>(
_context: &$crate::parser::ParserContext,
input: &mut ::cssparser::Parser<'i, 't>,
) -> Result<$name, ::style_traits::ParseError<'i>> {
try_match_ident_ignore_ascii_case! { input,
$( $css => Ok($name::$variant), )+
}
}
}
impl ::style_traits::ToCss for $name {
fn to_css<W>(
&self,
dest: &mut ::style_traits::CssWriter<W>,
) -> ::std::fmt::Result
where
W: ::std::fmt::Write,
{
match *self {
$( $name::$variant => dest.write_str($css) ),+
}
}
}
}
}
/// A macro for implementing `ToComputedValue`, and `Parse` traits for
/// the enums defined using `define_css_keyword_enum` macro.
///
/// NOTE: We should either move `Parse` trait to `style_traits`
/// or `define_css_keyword_enum` macro to this crate, but that
/// may involve significant cleanup in both the crates.
macro_rules! add_impls_for_keyword_enum {
($name:ident) => {
impl $crate::parser::Parse for $name {
#[inline]
fn parse<'i, 't>(
_context: &$crate::parser::ParserContext,
input: &mut ::cssparser::Parser<'i, 't>,
) -> Result<Self, ::style_traits::ParseError<'i>> {
$name::parse(input)
}
}
trivial_to_computed_value!($name);
};
}
macro_rules! define_keyword_type {
($name: ident, $css: expr) => {
#[allow(missing_docs)]

View File

@ -62,6 +62,7 @@ use values::computed::{NonNegativeLength, ToComputedValue, Percentage};
use values::computed::font::{FontSize, SingleFontFamily};
use values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use values::computed::outline::OutlineStyle;
use values::generics::transform::TransformStyle;
use computed_values::border_style;
pub mod style_structs {
@ -1426,29 +1427,21 @@ impl Clone for ${style_struct.gecko_struct_name} {
}
</%def>
<%def name="impl_font_settings(ident, tag_type)">
<%def name="impl_font_settings(ident, tag_type, value_type, gecko_value_type)">
<%
gecko_ffi_name = to_camel_case_lower(ident)
%>
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
use values::generics::FontSettings;
let current_settings = &mut self.gecko.mFont.${gecko_ffi_name};
current_settings.clear_pod();
match v {
FontSettings::Normal => (), // do nothing, length is already 0
unsafe { current_settings.set_len_pod(v.0.len() as u32) };
FontSettings::Tag(other_settings) => {
unsafe { current_settings.set_len_pod(other_settings.len() as u32) };
for (current, other) in current_settings.iter_mut().zip(other_settings) {
current.mTag = other.tag;
current.mValue = other.value.0;
}
}
};
for (current, other) in current_settings.iter_mut().zip(v.0.iter()) {
current.mTag = other.tag.0;
current.mValue = other.value as ${gecko_value_type};
}
}
pub fn copy_${ident}_from(&mut self, other: &Self) {
@ -1470,20 +1463,17 @@ impl Clone for ${style_struct.gecko_struct_name} {
}
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use values::generics::{FontSettings, FontSettingTag, ${tag_type}} ;
use values::generics::font::{FontSettings, ${tag_type}};
use values::specified::font::FontTag;
if self.gecko.mFont.${gecko_ffi_name}.len() == 0 {
FontSettings::Normal
} else {
FontSettings::Tag(
self.gecko.mFont.${gecko_ffi_name}.iter().map(|gecko_font_setting| {
FontSettingTag {
tag: gecko_font_setting.mTag,
value: ${tag_type}(gecko_font_setting.mValue),
}
}).collect()
)
}
FontSettings(
self.gecko.mFont.${gecko_ffi_name}.iter().map(|gecko_font_setting| {
${tag_type} {
tag: FontTag(gecko_font_setting.mTag),
value: gecko_font_setting.mValue as ${value_type},
}
}).collect::<Vec<_>>().into_boxed_slice()
)
}
</%def>
@ -2337,8 +2327,10 @@ fn static_assert() {
<%self:impl_trait style_struct_name="Font"
skip_longhands="${skip_font_longhands}">
<% impl_font_settings("font_feature_settings", "FontSettingTagInt") %>
<% impl_font_settings("font_variation_settings", "FontSettingTagFloat") %>
// Negative numbers are invalid at parse time, but <integer> is still an
// i32.
<% impl_font_settings("font_feature_settings", "FeatureTagValue", "i32", "u32") %>
<% impl_font_settings("font_variation_settings", "VariationValue", "f32", "f32") %>
pub fn fixup_none_generic(&mut self, device: &Device) {
self.gecko.mFont.systemFont = false;
@ -3345,6 +3337,25 @@ fn static_assert() {
self.copy_transition_property_from(other)
}
// Hand-written because the Mako helpers transform `Preserve3d` into `PRESERVE3D`.
pub fn set_transform_style(&mut self, v: TransformStyle) {
self.gecko.mTransformStyle = match v {
TransformStyle::Flat => structs::NS_STYLE_TRANSFORM_STYLE_FLAT as u8,
TransformStyle::Preserve3d => structs::NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D as u8,
};
}
// Hand-written because the Mako helpers transform `Preserve3d` into `PRESERVE3D`.
pub fn clone_transform_style(&self) -> TransformStyle {
match self.gecko.mTransformStyle as u32 {
structs::NS_STYLE_TRANSFORM_STYLE_FLAT => TransformStyle::Flat,
structs::NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D => TransformStyle::Preserve3d,
_ => panic!("illegal transform style"),
}
}
${impl_simple_copy('transform_style', 'mTransformStyle')}
${impl_transition_count('property', 'Property')}
pub fn animations_equals(&self, other: &Self) -> bool {
@ -5081,7 +5092,7 @@ fn static_assert() {
coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]);
coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]);
}
shape.mFillRule = if poly.fill == FillRule::EvenOdd {
shape.mFillRule = if poly.fill == FillRule::Evenodd {
StyleFillRule::Evenodd
} else {
StyleFillRule::Nonzero

View File

@ -424,20 +424,13 @@
use properties::longhands::system_font::SystemFont;
pub mod computed_value {
use cssparser::Parser;
use parser::{Parse, ParserContext};
use style_traits::ParseError;
define_css_keyword_enum! { T:
% for value in keyword.values_for(product):
"${value}" => ${to_camel_case(value)},
% endfor
}
impl Parse for T {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
T::parse(input)
}
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse)]
#[derive(PartialEq, ToCss)]
pub enum T {
% for value in keyword.values_for(product):
${to_camel_case(value)},
% endfor
}
${gecko_keyword_conversion(keyword, keyword.values_for(product), type="T", cast_to="i32")}
@ -604,26 +597,32 @@
<%def name="inner_body(keyword, extra_specified=None, needs_conversion=False)">
% if extra_specified or keyword.aliases_for(product):
define_css_keyword_enum! { SpecifiedValue:
values {
% for value in keyword.values_for(product) + (extra_specified or "").split():
"${value}" => ${to_camel_case(value)},
% endfor
}
aliases {
% for alias, value in keyword.aliases_for(product).iteritems():
"${alias}" => ${to_camel_case(value)},
% endfor
}
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum SpecifiedValue {
% for value in keyword.values_for(product) + (extra_specified or "").split():
<%
aliases = []
for alias, v in keyword.aliases_for(product).iteritems():
if value == v:
aliases.append(alias)
%>
% if aliases:
#[css(aliases = "${','.join(aliases)}")]
% endif
${to_camel_case(value)},
% endfor
}
% else:
pub use self::computed_value::T as SpecifiedValue;
% endif
pub mod computed_value {
define_css_keyword_enum! { T:
% for value in data.longhands_by_name[name].keyword.values_for(product):
"${value}" => ${to_camel_case(value)},
% endfor
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum T {
% for value in data.longhands_by_name[name].keyword.values_for(product):
${to_camel_case(value)},
% endfor
}
}
#[inline]
@ -639,13 +638,6 @@
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input)
}
impl Parse for SpecifiedValue {
#[inline]
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<SpecifiedValue, ParseError<'i>> {
SpecifiedValue::parse(input)
}
}
% if needs_conversion:
<%

View File

@ -17,8 +17,6 @@ use properties::{CSSWideKeyword, PropertyDeclaration};
use properties::longhands;
use properties::longhands::font_weight::computed_value::T as FontWeight;
use properties::longhands::font_stretch::computed_value::T as FontStretch;
#[cfg(feature = "gecko")]
use properties::longhands::font_variation_settings::computed_value::T as FontVariationSettings;
use properties::longhands::visibility::computed_value::T as Visibility;
#[cfg(feature = "gecko")]
use properties::PropertyId;
@ -51,14 +49,15 @@ use values::computed::transform::Translate as ComputedTranslate;
use values::computed::transform::Scale as ComputedScale;
use values::generics::transform::{self, Rotate, Translate, Scale, Transform, TransformOperation};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
#[cfg(feature = "gecko")] use values::generics::FontSettings as GenericFontSettings;
#[cfg(feature = "gecko")] use values::generics::FontSettingTag as GenericFontSettingTag;
#[cfg(feature = "gecko")] use values::generics::FontSettingTagFloat;
use values::generics::font::FontSettings as GenericFontSettings;
use values::computed::font::FontVariationSettings;
use values::generics::font::VariationValue;
use values::generics::NonNegative;
use values::generics::effects::Filter;
use values::generics::position as generic_position;
use values::generics::svg::{SVGLength, SvgLengthOrPercentageOrNumber, SVGPaint};
use values::generics::svg::{SVGPaintKind, SVGStrokeDashArray, SVGOpacity};
use values::specified::font::FontTag;
/// <https://drafts.csswg.org/css-transitions/#animtype-repeatable-list>
pub trait RepeatableListAnimatable: Animate {}
@ -816,18 +815,16 @@ impl Into<FontStretch> for f64 {
}
/// <https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def>
#[cfg(feature = "gecko")]
impl Animate for FontVariationSettings {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
FontSettingTagIter::new(self, other)?
.map(|r| r.and_then(|(st, ot)| st.animate(&ot, procedure)))
.collect::<Result<Vec<FontSettingTag>, ()>>()
.map(GenericFontSettings::Tag)
.collect::<Result<Vec<ComputedVariationValue>, ()>>()
.map(|v| GenericFontSettings(v.into_boxed_slice()))
}
}
#[cfg(feature = "gecko")]
impl ComputeSquaredDistance for FontVariationSettings {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
@ -837,7 +834,6 @@ impl ComputeSquaredDistance for FontVariationSettings {
}
}
#[cfg(feature = "gecko")]
impl ToAnimatedZero for FontVariationSettings {
#[inline]
fn to_animated_zero(&self) -> Result<Self, ()> {
@ -845,49 +841,21 @@ impl ToAnimatedZero for FontVariationSettings {
}
}
#[cfg(feature = "gecko")]
impl Animate for FontSettingTag {
#[inline]
fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
if self.tag != other.tag {
return Err(());
}
let value = self.value.animate(&other.value, procedure)?;
Ok(FontSettingTag {
tag: self.tag,
value,
})
}
}
type ComputedVariationValue = VariationValue<Number>;
#[cfg(feature = "gecko")]
impl ComputeSquaredDistance for FontSettingTag {
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
if self.tag != other.tag {
return Err(());
}
self.value.compute_squared_distance(&other.value)
}
}
#[cfg(feature = "gecko")]
type FontSettingTag = GenericFontSettingTag<FontSettingTagFloat>;
#[cfg(feature = "gecko")]
// FIXME: Could do a rename, this is only used for font variations.
struct FontSettingTagIterState<'a> {
tags: Vec<(&'a FontSettingTag)>,
tags: Vec<(&'a ComputedVariationValue)>,
index: usize,
prev_tag: u32,
prev_tag: FontTag,
}
#[cfg(feature = "gecko")]
impl<'a> FontSettingTagIterState<'a> {
fn new(tags: Vec<(&'a FontSettingTag)>) -> FontSettingTagIterState<'a> {
fn new(tags: Vec<<&'a ComputedVariationValue>) -> FontSettingTagIterState<'a> {
FontSettingTagIterState {
index: tags.len(),
tags,
prev_tag: 0,
prev_tag: FontTag(0),
}
}
}
@ -897,12 +865,13 @@ impl<'a> FontSettingTagIterState<'a> {
/// [CSS fonts level 4](https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-variation-settings)
/// defines the animation of font-variation-settings as follows:
///
/// Two declarations of font-feature-settings[sic] can be animated between if they are "like".
/// "Like" declarations are ones where the same set of properties appear (in any order).
/// Because succesive[sic] duplicate properties are applied instead of prior duplicate
/// properties, two declarations can be "like" even if they have differing number of
/// properties. If two declarations are "like" then animation occurs pairwise between
/// corresponding values in the declarations.
/// Two declarations of font-feature-settings[sic] can be animated between if
/// they are "like". "Like" declarations are ones where the same set of
/// properties appear (in any order). Because succesive[sic] duplicate
/// properties are applied instead of prior duplicate properties, two
/// declarations can be "like" even if they have differing number of
/// properties. If two declarations are "like" then animation occurs pairwise
/// between corresponding values in the declarations.
///
/// In other words if we have the following lists:
///
@ -914,9 +883,10 @@ impl<'a> FontSettingTagIterState<'a> {
/// "wdth" 5, "wght" 2
/// "wght" 4, "wdth" 10
///
/// This iterator supports this by sorting the two lists, then iterating them in reverse,
/// and skipping entries with repeated tag names. It will return Some(Err()) if it reaches the
/// end of one list before the other, or if the tag names do not match.
/// This iterator supports this by sorting the two lists, then iterating them in
/// reverse, and skipping entries with repeated tag names. It will return
/// Some(Err()) if it reaches the end of one list before the other, or if the
/// tag names do not match.
///
/// For the above example, this iterator would return:
///
@ -924,37 +894,33 @@ impl<'a> FontSettingTagIterState<'a> {
/// Some(Ok("wdth" 5, "wdth" 10))
/// None
///
#[cfg(feature = "gecko")]
struct FontSettingTagIter<'a> {
a_state: FontSettingTagIterState<'a>,
b_state: FontSettingTagIterState<'a>,
}
#[cfg(feature = "gecko")]
impl<'a> FontSettingTagIter<'a> {
fn new(
a_settings: &'a FontVariationSettings,
b_settings: &'a FontVariationSettings,
) -> Result<FontSettingTagIter<'a>, ()> {
if let (&GenericFontSettings::Tag(ref a_tags), &GenericFontSettings::Tag(ref b_tags)) = (a_settings, b_settings)
{
fn as_new_sorted_tags(tags: &Vec<FontSettingTag>) -> Vec<(&FontSettingTag)> {
use std::iter::FromIterator;
let mut sorted_tags: Vec<(&FontSettingTag)> = Vec::from_iter(tags.iter());
sorted_tags.sort_by_key(|k| k.tag);
sorted_tags
};
Ok(FontSettingTagIter {
a_state: FontSettingTagIterState::new(as_new_sorted_tags(a_tags)),
b_state: FontSettingTagIterState::new(as_new_sorted_tags(b_tags)),
})
} else {
Err(())
if a_settings.0.is_empty() || b_settings.0.is_empty() {
return Err(());
}
fn as_new_sorted_tags(tags: &[ComputedVariationValue]) -> Vec<<&ComputedVariationValue> {
use std::iter::FromIterator;
let mut sorted_tags = Vec::from_iter(tags.iter());
sorted_tags.sort_by_key(|k| k.tag.0);
sorted_tags
};
Ok(FontSettingTagIter {
a_state: FontSettingTagIterState::new(as_new_sorted_tags(&a_settings.0)),
b_state: FontSettingTagIterState::new(as_new_sorted_tags(&b_settings.0)),
})
}
fn next_tag(state: &mut FontSettingTagIterState<'a>) -> Option<(&'a FontSettingTag)> {
fn next_tag(state: &mut FontSettingTagIterState<'a>) -> Option<<&'a ComputedVariationValue> {
if state.index == 0 {
return None;
}
@ -970,11 +936,10 @@ impl<'a> FontSettingTagIter<'a> {
}
}
#[cfg(feature = "gecko")]
impl<'a> Iterator for FontSettingTagIter<'a> {
type Item = Result<(&'a FontSettingTag, &'a FontSettingTag), ()>;
type Item = Result<(&'a ComputedVariationValue, &'a ComputedVariationValue), ()>;
fn next(&mut self) -> Option<Result<(&'a FontSettingTag, &'a FontSettingTag), ()>> {
fn next(&mut self) -> Option<Result<(&'a ComputedVariationValue, &'a ComputedVariationValue), ()>> {
match (
FontSettingTagIter::next_tag(&mut self.a_state),
FontSettingTagIter::next_tag(&mut self.b_state),

View File

@ -32,13 +32,16 @@
ignored_when_colors_disabled=True,
)}
${helpers.predefined_type("border-%s-style" % side_name, "BorderStyle",
"specified::BorderStyle::None",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
spec=maybe_logical_spec(side, "style"),
flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="discrete" if not is_logical else "none",
logical=is_logical)}
${helpers.predefined_type(
"border-%s-style" % side_name, "BorderStyle",
"specified::BorderStyle::None",
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
spec=maybe_logical_spec(side, "style"),
flags="APPLIES_TO_FIRST_LETTER",
animation_value_type="discrete" if not is_logical else "none",
logical=is_logical,
needs_context=False,
)}
${helpers.predefined_type("border-%s-width" % side_name,
"BorderSideWidth",
@ -112,11 +115,14 @@ ${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
pub struct SpecifiedValue(pub RepeatKeyword,
pub Option<RepeatKeyword>);
define_css_keyword_enum!(RepeatKeyword:
"stretch" => Stretch,
"repeat" => Repeat,
"round" => Round,
"space" => Space);
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum RepeatKeyword {
Stretch,
Repeat,
Round,
Space,
}
#[inline]
pub fn get_initial_value() -> computed_value::T {

View File

@ -526,14 +526,16 @@ ${helpers.single_keyword("transform-box",
gecko_inexhaustive="True",
animation_value_type="discrete")}
// `auto` keyword is not supported in gecko yet.
${helpers.single_keyword("transform-style",
"auto flat preserve-3d" if product == "servo" else
"flat preserve-3d",
spec="https://drafts.csswg.org/css-transforms/#transform-style-property",
extra_prefixes="moz webkit",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
animation_value_type="discrete")}
${helpers.predefined_type(
"transform-style",
"TransformStyle",
"computed::TransformStyle::" + ("Auto" if product == "servo" else "Flat"),
spec="https://drafts.csswg.org/css-transforms-2/#transform-style-property",
needs_context=False,
extra_prefixes="moz webkit",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
animation_value_type="discrete",
)}
${helpers.predefined_type("transform-origin",
"TransformOrigin",

View File

@ -144,7 +144,6 @@ ${helpers.predefined_type("font-feature-settings",
initial_value="computed::FontFeatureSettings::normal()",
initial_specified_value="specified::FontFeatureSettings::normal()",
extra_prefixes="moz",
boxed=True,
animation_value_type="discrete",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-fonts/#propdef-font-feature-settings")}
@ -157,10 +156,10 @@ https://drafts.csswg.org/css-fonts-4/#low-level-font-variation-settings-control-
%>
${helpers.predefined_type("font-variation-settings",
"FontVariantSettings",
"FontVariationSettings",
products="gecko",
gecko_pref="layout.css.font-variations.enabled",
initial_value="specified::FontVariantSettings::normal()",
initial_value="computed::FontVariationSettings::normal()",
animation_value_type="ComputedValue",
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="${variation_spec}")}

View File

@ -279,12 +279,14 @@ ${helpers.predefined_type(
}
}
define_css_keyword_enum!(ShapeKeyword:
"dot" => Dot,
"circle" => Circle,
"double-circle" => DoubleCircle,
"triangle" => Triangle,
"sesame" => Sesame);
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum ShapeKeyword {
Dot,
Circle,
DoubleCircle,
Triangle,
Sesame,
}
impl ShapeKeyword {
pub fn char(&self, fill: bool) -> &str {
@ -381,14 +383,19 @@ ${helpers.predefined_type(
<%helpers:longhand name="text-emphasis-position" animation_value_type="discrete" products="gecko"
spec="https://drafts.csswg.org/css-text-decor/#propdef-text-emphasis-position">
define_css_keyword_enum!(HorizontalWritingModeValue:
"over" => Over,
"under" => Under);
add_impls_for_keyword_enum!(VerticalWritingModeValue);
define_css_keyword_enum!(VerticalWritingModeValue:
"right" => Right,
"left" => Left);
add_impls_for_keyword_enum!(HorizontalWritingModeValue);
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum HorizontalWritingModeValue {
Over,
Under,
}
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum VerticalWritingModeValue {
Right,
Left,
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct SpecifiedValue(pub HorizontalWritingModeValue, pub VerticalWritingModeValue);

View File

@ -9,9 +9,13 @@ ${helpers.four_sides_shorthand("border-color", "border-%s-color", "specified::Co
spec="https://drafts.csswg.org/css-backgrounds/#border-color",
allow_quirks=True)}
${helpers.four_sides_shorthand("border-style", "border-%s-style",
"specified::BorderStyle::parse",
spec="https://drafts.csswg.org/css-backgrounds/#border-style")}
${helpers.four_sides_shorthand(
"border-style",
"border-%s-style",
"specified::BorderStyle::parse",
needs_context=False,
spec="https://drafts.csswg.org/css-backgrounds/#border-style",
)}
<%helpers:shorthand name="border-width" sub_properties="${
' '.join('border-%s-width' % side
@ -63,7 +67,7 @@ pub fn parse_border<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
}
}
if style.is_none() {
if let Ok(value) = input.try(|i| BorderStyle::parse(context, i)) {
if let Ok(value) = input.try(BorderStyle::parse) {
style = Some(value);
any = true;
continue

View File

@ -22,13 +22,13 @@ use std::slice;
use style_traits::{CssWriter, ParseError, ToCss};
use values::CSSFloat;
use values::animated::{ToAnimatedValue, ToAnimatedZero};
use values::computed::{Context, NonNegativeLength, ToComputedValue};
use values::generics::{FontSettings, FontSettingTagInt};
use values::computed::{Context, NonNegativeLength, ToComputedValue, Integer, Number};
use values::generics::font::{FontSettings, FeatureTagValue, VariationValue};
use values::specified::font as specified;
use values::specified::length::{FontBaseSize, NoCalcLength};
pub use values::computed::Length as MozScriptMinSize;
pub use values::specified::font::{XTextZoom, XLang, MozScriptSizeMultiplier, FontSynthesis, FontVariantSettings};
pub use values::specified::font::{XTextZoom, XLang, MozScriptSizeMultiplier, FontSynthesis};
/// As of CSS Fonts Module Level 3, only the following values are
/// valid: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900
@ -712,8 +712,11 @@ pub type FontVariantLigatures = specified::VariantLigatures;
/// Use VariantNumeric as computed type of FontVariantNumeric
pub type FontVariantNumeric = specified::VariantNumeric;
/// Use FontSettings as computed type of FontFeatureSettings
pub type FontFeatureSettings = FontSettings<FontSettingTagInt>;
/// Use FontSettings as computed type of FontFeatureSettings.
pub type FontFeatureSettings = FontSettings<FeatureTagValue<Integer>>;
/// The computed value for font-variation-settings.
pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
/// font-language-override can only have a single three-letter
/// OpenType "language system" tag, so we should be able to compute

View File

@ -40,7 +40,7 @@ pub use self::background::{BackgroundSize, BackgroundRepeat};
pub use self::border::{BorderImageSlice, BorderImageWidth, BorderImageSideWidth};
pub use self::border::{BorderRadius, BorderCornerRadius, BorderSpacing};
pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariationSettings, FontVariantEastAsian};
pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain};
@ -73,7 +73,8 @@ pub use self::svg::MozContextProperties;
pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextAlign, TextOverflow, WordSpacing};
pub use self::time::Time;
pub use self::transform::{TimingFunction, Transform, TransformOperation, TransformOrigin, Rotate, Translate, Scale};
pub use self::transform::{Rotate, Scale, TimingFunction, Transform, TransformOperation};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
pub use self::ui::MozForceBrokenImageIcon;
#[cfg(feature = "gecko")]

View File

@ -18,6 +18,8 @@ use values::generics::transform::TimingFunction as GenericTimingFunction;
use values::generics::transform::TransformOrigin as GenericTransformOrigin;
use values::generics::transform::Translate as GenericTranslate;
pub use values::generics::transform::TransformStyle;
/// A single operation in a computed CSS `transform`
pub type TransformOperation = GenericTransformOperation<
Angle,

View File

@ -30,13 +30,16 @@ pub enum GeometryBox {
pub type FloatAreaShape<BasicShape, Image> = ShapeSource<BasicShape, ShapeBox, Image>;
// https://drafts.csswg.org/css-shapes-1/#typedef-shape-box
define_css_keyword_enum!(ShapeBox:
"margin-box" => MarginBox,
"border-box" => BorderBox,
"padding-box" => PaddingBox,
"content-box" => ContentBox
);
add_impls_for_keyword_enum!(ShapeBox);
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum ShapeBox {
MarginBox,
BorderBox,
PaddingBox,
ContentBox,
}
/// A shape source, for some reference box.
#[allow(missing_docs)]
@ -117,11 +120,14 @@ pub struct Polygon<LengthOrPercentage> {
// NOTE: Basic shapes spec says that these are the only two values, however
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
// says that it can also be `inherit`
define_css_keyword_enum!(FillRule:
"nonzero" => NonZero,
"evenodd" => EvenOdd
);
add_impls_for_keyword_enum!(FillRule);
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum FillRule {
Nonzero,
Evenodd,
}
// FIXME(nox): Implement ComputeSquaredDistance for T types and stop
// using PartialEq here, this will let us derive this impl.
@ -239,5 +245,5 @@ impl<L: ToCss> ToCss for Polygon<L> {
impl Default for FillRule {
#[inline]
fn default() -> Self { FillRule::NonZero }
fn default() -> Self { FillRule::Nonzero }
}

View File

@ -0,0 +1,119 @@
/* 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/. */
//! Generic types for font stuff.
use cssparser::Parser;
use num_traits::One;
use parser::{Parse, ParserContext};
use std::fmt::{self, Write};
use style_traits::{CssWriter, ParseError, ToCss};
use values::distance::{ComputeSquaredDistance, SquaredDistance};
use values::specified::font::FontTag;
/// https://drafts.csswg.org/css-fonts-4/#feature-tag-value
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FeatureTagValue<Integer> {
/// A four-character tag, packed into a u32 (one byte per character).
pub tag: FontTag,
/// The actual value.
pub value: Integer,
}
impl<Integer> ToCss for FeatureTagValue<Integer>
where
Integer: One + ToCss + PartialEq,
{
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.tag.to_css(dest)?;
// Don't serialize the default value.
if self.value != Integer::one() {
dest.write_char(' ')?;
self.value.to_css(dest)?;
}
Ok(())
}
}
/// Variation setting for a single feature, see:
///
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
#[derive(Animate, Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub struct VariationValue<Number> {
/// A four-character tag, packed into a u32 (one byte per character).
#[animation(constant)]
pub tag: FontTag,
/// The actual value.
pub value: Number,
}
impl<Number> ComputeSquaredDistance for VariationValue<Number>
where
Number: ComputeSquaredDistance,
{
#[inline]
fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
if self.tag != other.tag {
return Err(());
}
self.value.compute_squared_distance(&other.value)
}
}
/// A value both for font-variation-settings and font-feature-settings.
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FontSettings<T>(pub Box<[T]>);
impl<T> FontSettings<T> {
/// Default value of font settings as `normal`.
#[inline]
pub fn normal() -> Self {
FontSettings(vec![].into_boxed_slice())
}
}
impl<T: Parse> Parse for FontSettings<T> {
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(Self::normal());
}
Ok(FontSettings(
input.parse_comma_separated(|i| T::parse(context, i))?.into_boxed_slice()
))
}
}
impl<T: ToCss> ToCss for FontSettings<T> {
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
if self.0.is_empty() {
return dest.write_str("normal");
}
let mut first = true;
for item in self.0.iter() {
if !first {
dest.write_str(", ")?;
}
first = false;
item.to_css(dest)?;
}
Ok(())
}
}

View File

@ -140,12 +140,15 @@ impl Parse for GridLine<specified::Integer> {
}
}
define_css_keyword_enum!{ TrackKeyword:
"auto" => Auto,
"max-content" => MaxContent,
"min-content" => MinContent
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum TrackKeyword {
Auto,
MaxContent,
MinContent,
}
add_impls_for_keyword_enum!(TrackKeyword);
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.

View File

@ -97,15 +97,18 @@ pub enum Ellipse<LengthOrPercentage> {
}
/// <https://drafts.csswg.org/css-images/#typedef-extent-keyword>
define_css_keyword_enum!(ShapeExtent:
"closest-side" => ClosestSide,
"farthest-side" => FarthestSide,
"closest-corner" => ClosestCorner,
"farthest-corner" => FarthestCorner,
"contain" => Contain,
"cover" => Cover
);
add_impls_for_keyword_enum!(ShapeExtent);
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum ShapeExtent {
ClosestSide,
FarthestSide,
ClosestCorner,
FarthestCorner,
Contain,
Cover,
}
/// A gradient item.
/// <https://drafts.csswg.org/css-images-4/#color-stop-syntax>

View File

@ -8,9 +8,7 @@
use counter_style::{Symbols, parse_counter_style_name};
use cssparser::Parser;
use parser::{Parse, ParserContext};
use std::fmt::{self, Write};
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
use style_traits::{StyleParseErrorKind, ToCss};
use style_traits::{ParseError, StyleParseErrorKind};
use super::CustomIdent;
pub mod background;
@ -20,6 +18,7 @@ pub mod border;
pub mod box_;
pub mod effects;
pub mod flex;
pub mod font;
#[cfg(feature = "gecko")]
pub mod gecko;
pub mod grid;
@ -32,14 +31,17 @@ pub mod text;
pub mod transform;
// https://drafts.csswg.org/css-counter-styles/#typedef-symbols-type
define_css_keyword_enum! { SymbolsType:
"cyclic" => Cyclic,
"numeric" => Numeric,
"alphabetic" => Alphabetic,
"symbolic" => Symbolic,
"fixed" => Fixed,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum SymbolsType {
Cyclic,
Numeric,
Alphabetic,
Symbolic,
Fixed,
}
add_impls_for_keyword_enum!(SymbolsType);
#[cfg(feature = "gecko")]
impl SymbolsType {
@ -128,167 +130,6 @@ impl Parse for CounterStyleOrNone {
}
}
/// A settings tag, defined by a four-character tag and a setting value
///
/// For font-feature-settings, this is a tag and an integer,
/// for font-variation-settings this is a tag and a float
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FontSettingTag<T> {
/// A four-character tag, packed into a u32 (one byte per character)
pub tag: u32,
/// The value
pub value: T,
}
impl<T> OneOrMoreSeparated for FontSettingTag<T> {
type S = Comma;
}
impl<T: ToCss> ToCss for FontSettingTag<T> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
use byteorder::{BigEndian, ByteOrder};
use std::str;
let mut raw = [0u8; 4];
BigEndian::write_u32(&mut raw, self.tag);
str::from_utf8(&raw).unwrap_or_default().to_css(dest)?;
self.value.to_css(dest)
}
}
impl<T: Parse> Parse for FontSettingTag<T> {
/// <https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings>
/// <https://drafts.csswg.org/css-fonts-4/#low-level-font-variation->
/// settings-control-the-font-variation-settings-property
/// <string> [ on | off | <integer> ]
/// <string> <number>
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
use byteorder::{ReadBytesExt, BigEndian};
use std::io::Cursor;
let u_tag;
{
let location = input.current_source_location();
let tag = input.expect_string()?;
// allowed strings of length 4 containing chars: <U+20, U+7E>
if tag.len() != 4 ||
tag.chars().any(|c| c < ' ' || c > '~')
{
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
let mut raw = Cursor::new(tag.as_bytes());
u_tag = raw.read_u32::<BigEndian>().unwrap();
}
Ok(FontSettingTag { tag: u_tag, value: T::parse(context, input)? })
}
}
/// A font settings value for font-variation-settings or font-feature-settings
#[derive(Clone, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
pub enum FontSettings<T> {
/// No settings (default)
Normal,
/// Set of settings
Tag(Vec<FontSettingTag<T>>)
}
impl <T> FontSettings<T> {
#[inline]
/// Default value of font settings as `normal`
pub fn normal() -> Self {
FontSettings::Normal
}
}
impl<T: Parse> Parse for FontSettings<T> {
/// <https://www.w3.org/TR/css-fonts-3/#propdef-font-feature-settings>
fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("normal")).is_ok() {
return Ok(FontSettings::Normal);
}
Vec::parse(context, input).map(FontSettings::Tag)
}
}
/// An integer that can also parse "on" and "off",
/// for font-feature-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FontSettingTagInt(pub u32);
/// A number value to be used for font-variation-settings
///
/// Do not use this type anywhere except within FontSettings
/// because it serializes with the preceding space
#[cfg_attr(feature = "gecko", derive(Animate, ComputeSquaredDistance))]
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FontSettingTagFloat(pub f32);
impl ToCss for FontSettingTagInt {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
match self.0 {
1 => Ok(()),
0 => dest.write_str(" off"),
x => {
dest.write_char(' ')?;
x.to_css(dest)
}
}
}
}
impl Parse for FontSettingTagInt {
fn parse<'i, 't>(_context: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
if let Ok(value) = input.try(|input| input.expect_integer()) {
// handle integer, throw if it is negative
if value >= 0 {
Ok(FontSettingTagInt(value as u32))
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
} else if let Ok(_) = input.try(|input| input.expect_ident_matching("on")) {
// on is an alias for '1'
Ok(FontSettingTagInt(1))
} else if let Ok(_) = input.try(|input| input.expect_ident_matching("off")) {
// off is an alias for '0'
Ok(FontSettingTagInt(0))
} else {
// empty value is an alias for '1'
Ok(FontSettingTagInt(1))
}
}
}
impl Parse for FontSettingTagFloat {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<Self, ParseError<'i>> {
input.expect_number().map(FontSettingTagFloat).map_err(|e| e.into())
}
}
impl ToCss for FontSettingTagFloat {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
dest.write_str(" ")?;
self.0.to_css(dest)
}
}
/// A wrapper of Non-negative values.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Animate, Clone, ComputeSquaredDistance, Copy, Debug, MallocSizeOf)]

View File

@ -98,20 +98,26 @@ pub enum TimingFunction<Integer, Number> {
Frames(Integer),
}
define_css_keyword_enum! { TimingKeyword:
"linear" => Linear,
"ease" => Ease,
"ease-in" => EaseIn,
"ease-out" => EaseOut,
"ease-in-out" => EaseInOut,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum TimingKeyword {
Linear,
Ease,
EaseIn,
EaseOut,
EaseInOut,
}
add_impls_for_keyword_enum!(TimingKeyword);
define_css_keyword_enum! { StepPosition:
"start" => Start,
"end" => End,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum StepPosition {
Start,
End,
}
add_impls_for_keyword_enum!(StepPosition);
impl<H, V, D> TransformOrigin<H, V, D> {
/// Returns a new transform origin.
@ -714,3 +720,13 @@ pub enum Translate<LengthOrPercentage, Length> {
/// '<length-percentage> <length-percentage> <length>'
Translate3D(LengthOrPercentage, LengthOrPercentage, Length),
}
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
pub enum TransformStyle {
#[cfg(feature = "servo")]
Auto,
Flat,
#[css(keyword = "preserve-3d")]
Preserve3d,
}

View File

@ -195,10 +195,14 @@ impl ToCss for KeyframesName {
}
}
// A type for possible values for min- and max- flavors of width,
// height, block-size, and inline-size.
define_css_keyword_enum!(ExtremumLength:
"-moz-max-content" => MaxContent,
"-moz-min-content" => MinContent,
"-moz-fit-content" => FitContent,
"-moz-available" => FillAvailable);
/// A type for possible values for min- and max- flavors of width,
/// height, block-size, and inline-size.
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum ExtremumLength {
MozMaxContent,
MozMinContent,
MozFitContent,
MozAvailable,
}

View File

@ -28,9 +28,9 @@ pub enum Display {
Table, InlineTable, TableRowGroup, TableHeaderGroup,
TableFooterGroup, TableRow, TableColumnGroup,
TableColumn, TableCell, TableCaption, ListItem, None,
#[parse(aliases = "-webkit-flex")]
#[css(aliases = "-webkit-flex")]
Flex,
#[parse(aliases = "-webkit-inline-flex")]
#[css(aliases = "-webkit-inline-flex")]
InlineFlex,
#[cfg(feature = "gecko")]
Grid,
@ -320,25 +320,34 @@ impl Parse for AnimationName {
}
}
define_css_keyword_enum! { ScrollSnapType:
"none" => None,
"mandatory" => Mandatory,
"proximity" => Proximity,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum ScrollSnapType {
None,
Mandatory,
Proximity,
}
add_impls_for_keyword_enum!(ScrollSnapType);
define_css_keyword_enum! { OverscrollBehavior:
"auto" => Auto,
"contain" => Contain,
"none" => None,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum OverscrollBehavior {
Auto,
Contain,
None,
}
add_impls_for_keyword_enum!(OverscrollBehavior);
define_css_keyword_enum! { OverflowClipBox:
"padding-box" => PaddingBox,
"content-box" => ContentBox,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq)]
#[derive(ToComputedValue, ToCss)]
pub enum OverflowClipBox {
PaddingBox,
ContentBox,
}
add_impls_for_keyword_enum!(OverflowClipBox);
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss)]
/// Provides a rendering hint to the user agent,

View File

@ -47,12 +47,13 @@ pub enum Color {
#[cfg(feature = "gecko")]
mod gecko {
define_css_keyword_enum! { SpecialColorKeyword:
"-moz-default-color" => MozDefaultColor,
"-moz-default-background-color" => MozDefaultBackgroundColor,
"-moz-hyperlinktext" => MozHyperlinktext,
"-moz-activehyperlinktext" => MozActiveHyperlinktext,
"-moz-visitedhyperlinktext" => MozVisitedHyperlinktext,
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss)]
pub enum SpecialColorKeyword {
MozDefaultColor,
MozDefaultBackgroundColor,
MozHyperlinktext,
MozActiveHyperlinktext,
MozVisitedHyperlinktext,
}
}

View File

@ -21,8 +21,8 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
use values::CustomIdent;
use values::computed::{font as computed, Context, Length, NonNegativeLength, ToComputedValue};
use values::computed::font::{SingleFontFamily, FontFamilyList, FamilyName};
use values::generics::{FontSettings, FontSettingTagFloat};
use values::specified::{AllowQuirks, LengthOrPercentage, NoCalcLength, Number};
use values::generics::font::{FontSettings, FeatureTagValue, VariationValue};
use values::specified::{AllowQuirks, Integer, LengthOrPercentage, NoCalcLength, Number};
use values::specified::length::{AU_PER_PT, AU_PER_PX, FontBaseSize};
const DEFAULT_SCRIPT_MIN_SIZE_PT: u32 = 8;
@ -164,8 +164,8 @@ impl From<LengthOrPercentage> for FontSize {
}
}
/// Specifies a prioritized list of font family names or generic family names.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
/// Specifies a prioritized list of font family names or generic family names
pub enum FontFamily {
/// List of `font-family`
Values(FontFamilyList),
@ -1709,13 +1709,15 @@ impl Parse for FontVariantNumeric {
}
}
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, PartialEq, ToCss)]
/// Define initial settings that apply when the font defined
/// by an @font-face rule is rendered.
/// This property provides low-level control over OpenType or TrueType font variations.
pub type SpecifiedFontFeatureSettings = FontSettings<FeatureTagValue<Integer>>;
/// Define initial settings that apply when the font defined by an @font-face
/// rule is rendered.
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToCss)]
pub enum FontFeatureSettings {
/// Value of `FontSettings`
Value(computed::FontFeatureSettings),
Value(SpecifiedFontFeatureSettings),
/// System font
System(SystemFont)
}
@ -1724,7 +1726,7 @@ impl FontFeatureSettings {
#[inline]
/// Get default value of `font-feature-settings` as normal
pub fn normal() -> FontFeatureSettings {
FontFeatureSettings::Value(FontSettings::Normal)
FontFeatureSettings::Value(FontSettings::normal())
}
/// Get `font-feature-settings` with system font
@ -1745,12 +1747,12 @@ impl FontFeatureSettings {
impl ToComputedValue for FontFeatureSettings {
type ComputedValue = computed::FontFeatureSettings;
fn to_computed_value(&self, _context: &Context) -> computed::FontFeatureSettings {
fn to_computed_value(&self, context: &Context) -> computed::FontFeatureSettings {
match *self {
FontFeatureSettings::Value(ref v) => v.clone(),
FontFeatureSettings::Value(ref v) => v.to_computed_value(context),
FontFeatureSettings::System(_) => {
#[cfg(feature = "gecko")] {
_context.cached_system_font.as_ref().unwrap().font_feature_settings.clone()
context.cached_system_font.as_ref().unwrap().font_feature_settings.clone()
}
#[cfg(feature = "servo")] {
unreachable!()
@ -1760,7 +1762,7 @@ impl ToComputedValue for FontFeatureSettings {
}
fn from_computed_value(other: &computed::FontFeatureSettings) -> Self {
FontFeatureSettings::Value(other.clone())
FontFeatureSettings::Value(ToComputedValue::from_computed_value(other))
}
}
@ -1770,7 +1772,7 @@ impl Parse for FontFeatureSettings {
context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<FontFeatureSettings, ParseError<'i>> {
computed::FontFeatureSettings::parse(context, input).map(FontFeatureSettings::Value)
SpecifiedFontFeatureSettings::parse(context, input).map(FontFeatureSettings::Value)
}
}
@ -1962,8 +1964,95 @@ impl Parse for FontLanguageOverride {
}
}
/// This property provides low-level control over OpenType or TrueType font variations.
pub type FontVariantSettings = FontSettings<FontSettingTagFloat>;
/// A font four-character tag, represented as a u32 for convenience.
///
/// See:
/// https://drafts.csswg.org/css-fonts-4/#font-variation-settings-def
/// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-feature-settings
///
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, ToComputedValue)]
pub struct FontTag(pub u32);
impl Parse for FontTag {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
use byteorder::{ReadBytesExt, BigEndian};
use std::io::Cursor;
let location = input.current_source_location();
let tag = input.expect_string()?;
// allowed strings of length 4 containing chars: <U+20, U+7E>
if tag.len() != 4 || tag.as_bytes().iter().any(|c| *c < b' ' || *c > b'~') {
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}
let mut raw = Cursor::new(tag.as_bytes());
Ok(FontTag(raw.read_u32::<BigEndian>().unwrap()))
}
}
impl ToCss for FontTag {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
use byteorder::{BigEndian, ByteOrder};
use std::str;
let mut raw = [0u8; 4];
BigEndian::write_u32(&mut raw, self.0);
str::from_utf8(&raw).unwrap_or_default().to_css(dest)
}
}
/// This property provides low-level control over OpenType or TrueType font
/// variations.
pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
fn parse_one_feature_value<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Integer, ParseError<'i>> {
if let Ok(integer) = input.try(|i| Integer::parse_non_negative(context, i)) {
return Ok(integer)
}
try_match_ident_ignore_ascii_case! { input,
"on" => Ok(Integer::new(1)),
"off" => Ok(Integer::new(0)),
}
}
impl Parse for FeatureTagValue<Integer> {
/// https://drafts.csswg.org/css-fonts-4/#feature-tag-value
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let tag = FontTag::parse(context, input)?;
let value = input.try(|i| parse_one_feature_value(context, i))
.unwrap_or_else(|_| Integer::new(1));
Ok(Self { tag, value })
}
}
impl Parse for VariationValue<Number> {
/// This is the `<string> <number>` part of the font-variation-settings
/// syntax.
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let tag = FontTag::parse(context, input)?;
let value = Number::parse(context, input)?;
Ok(Self { tag, value })
}
}
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue)]
/// text-zoom. Enable if true, disable if false
@ -2060,6 +2149,7 @@ pub enum MozScriptLevel {
impl Parse for MozScriptLevel {
fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>) -> Result<MozScriptLevel, ParseError<'i>> {
// We don't bother to handle calc here.
if let Ok(i) = input.try(|i| i.expect_integer()) {
return Ok(MozScriptLevel::Relative(i))
}

View File

@ -825,8 +825,10 @@ impl LengthOrPercentage {
/// Parse a length, treating dimensionless numbers as pixels
///
/// <https://www.w3.org/TR/SVG2/types.html#presentation-attribute-css-value>
pub fn parse_numbers_are_pixels<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentage, ParseError<'i>> {
pub fn parse_numbers_are_pixels<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<LengthOrPercentage, ParseError<'i>> {
if let Ok(lop) = input.try(|i| Self::parse(context, i)) {
return Ok(lop)
}
@ -840,9 +842,10 @@ impl LengthOrPercentage {
/// Parse a non-negative length, treating dimensionless numbers as pixels
///
/// This is nonstandard behavior used by Firefox for SVG
pub fn parse_numbers_are_pixels_non_negative<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<LengthOrPercentage, ParseError<'i>> {
pub fn parse_numbers_are_pixels_non_negative<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<LengthOrPercentage, ParseError<'i>> {
if let Ok(lop) = input.try(|i| Self::parse_non_negative(context, i)) {
return Ok(lop)
}

View File

@ -9,6 +9,7 @@
use Namespace;
use context::QuirksMode;
use cssparser::{Parser, Token, serialize_identifier};
use num_traits::One;
use parser::{ParserContext, Parse};
use self::url::SpecifiedUrl;
#[allow(unused_imports)] use std::ascii::AsciiExt;
@ -33,7 +34,7 @@ pub use self::background::{BackgroundRepeat, BackgroundSize};
pub use self::border::{BorderCornerRadius, BorderImageSlice, BorderImageWidth};
pub use self::border::{BorderImageSideWidth, BorderRadius, BorderSideWidth, BorderSpacing};
pub use self::font::{FontSize, FontSizeAdjust, FontSynthesis, FontWeight, FontVariantAlternates};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariantSettings, FontVariantEastAsian};
pub use self::font::{FontFamily, FontLanguageOverride, FontVariationSettings, FontVariantEastAsian};
pub use self::font::{FontVariantLigatures, FontVariantNumeric, FontFeatureSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XTextZoom, XLang};
pub use self::box_::{AnimationIterationCount, AnimationName, Display, OverscrollBehavior, Contain};
@ -69,7 +70,8 @@ pub use self::table::XSpan;
pub use self::text::{InitialLetter, LetterSpacing, LineHeight, TextDecorationLine};
pub use self::text::{TextAlign, TextAlignKeyword, TextOverflow, WordSpacing};
pub use self::time::Time;
pub use self::transform::{TimingFunction, Transform, TransformOrigin, Rotate, Translate, Scale};
pub use self::transform::{Rotate, Scale, TimingFunction, Transform};
pub use self::transform::{TransformOrigin, TransformStyle, Translate};
pub use self::ui::MozForceBrokenImageIcon;
pub use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
@ -160,20 +162,23 @@ fn parse_number_with_clamping_mode<'i, 't>(
// 17.6.2.1. Higher values override lower values.
//
// FIXME(emilio): Should move to border.rs
define_numbered_css_keyword_enum! { BorderStyle:
"none" => None = -1,
"solid" => Solid = 6,
"double" => Double = 7,
"dotted" => Dotted = 4,
"dashed" => Dashed = 5,
"hidden" => Hidden = -2,
"groove" => Groove = 1,
"ridge" => Ridge = 3,
"inset" => Inset = 0,
"outset" => Outset = 2,
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Ord, Parse, PartialEq)]
#[derive(PartialOrd, ToCss)]
pub enum BorderStyle {
None = -1,
Solid = 6,
Double = 7,
Dotted = 4,
Dashed = 5,
Hidden = -2,
Groove = 1,
Ridge = 3,
Inset = 0,
Outset = 2,
}
impl BorderStyle {
/// Whether this border style is either none or hidden.
pub fn none_or_hidden(&self) -> bool {
@ -382,12 +387,28 @@ impl ToComputedValue for Opacity {
/// An specified `<integer>`, optionally coming from a `calc()` expression.
///
/// <https://drafts.csswg.org/css-values/#integers>
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq, PartialOrd)]
pub struct Integer {
value: CSSInteger,
was_calc: bool,
}
impl One for Integer {
#[inline]
fn one() -> Self {
Self::new(1)
}
}
// This is not great, because it loses calc-ness, but it's necessary for One.
impl ::std::ops::Mul<Integer> for Integer {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self::new(self.value * other.value)
}
}
impl Integer {
/// Trivially constructs a new `Integer` value.
pub fn new(val: CSSInteger) -> Self {
@ -435,7 +456,7 @@ impl Integer {
pub fn parse_with_minimum<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
min: i32
min: i32,
) -> Result<Integer, ParseError<'i>> {
match Integer::parse(context, input) {
// FIXME(emilio): The spec asks us to avoid rejecting it at parse
@ -498,10 +519,11 @@ impl ToCss for Integer {
pub type IntegerOrAuto = Either<Integer, Auto>;
impl IntegerOrAuto {
#[allow(missing_docs)]
pub fn parse_positive<'i, 't>(context: &ParserContext,
input: &mut Parser<'i, 't>)
-> Result<IntegerOrAuto, ParseError<'i>> {
/// Parse `auto` or a positive integer.
pub fn parse_positive<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<IntegerOrAuto, ParseError<'i>> {
match IntegerOrAuto::parse(context, input) {
Ok(Either::First(integer)) if integer.value() <= 0 => {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))

View File

@ -39,10 +39,10 @@ impl OutlineStyle {
impl Parse for OutlineStyle {
fn parse<'i, 't>(
context: &ParserContext,
_context: &ParserContext,
input: &mut Parser<'i, 't>
) -> Result<OutlineStyle, ParseError<'i>> {
if let Ok(border_style) = input.try(|i| BorderStyle::parse(context, i)) {
if let Ok(border_style) = input.try(BorderStyle::parse) {
if let BorderStyle::Hidden = border_style {
return Err(input.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("hidden".into())));
}

View File

@ -22,6 +22,8 @@ use values::specified::{self, Angle, Number, Length, Integer};
use values::specified::{LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrNumber};
use values::specified::position::{Side, X, Y};
pub use values::generics::transform::TransformStyle;
/// A single operation in a specified CSS `transform`
pub type TransformOperation = GenericTransformOperation<
Angle,

View File

@ -39,7 +39,7 @@ pub fn derive_to_animated_value(stream: TokenStream) -> TokenStream {
to_animated_value::derive(input).to_string().parse().unwrap()
}
#[proc_macro_derive(Parse, attributes(parse))]
#[proc_macro_derive(Parse, attributes(css))]
pub fn derive_parse(stream: TokenStream) -> TokenStream {
let input = syn::parse_derive_input(&stream.to_string()).unwrap();
parse::derive(input).to_string().parse().unwrap()

View File

@ -6,6 +6,7 @@ use cg;
use quote::Tokens;
use syn::DeriveInput;
use synstructure;
use to_css::CssVariantAttrs;
pub fn derive(input: DeriveInput) -> Tokens {
let name = &input.ident;
@ -19,8 +20,10 @@ pub fn derive(input: DeriveInput) -> Tokens {
"Parse is only supported for single-variant enums for now"
);
let variant_attrs = cg::parse_variant_attrs::<ParseVariantAttrs>(variant);
let identifier = cg::to_css_identifier(variant.ident.as_ref());
let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(variant);
let identifier = cg::to_css_identifier(
&variant_attrs.keyword.as_ref().unwrap_or(&variant.ident).as_ref(),
);
let ident = &variant.ident;
match_body = quote! {
@ -87,11 +90,3 @@ pub fn derive(input: DeriveInput) -> Tokens {
#methods_impl
}
}
#[darling(attributes(parse), default)]
#[derive(Default, FromVariant)]
struct ParseVariantAttrs {
/// The comma-separated list of aliases this variant should be aliased to at
/// parse time.
aliases: Option<String>,
}

View File

@ -23,10 +23,19 @@ pub fn derive(input: DeriveInput) -> Tokens {
if variant_attrs.dimension {
assert_eq!(bindings.len(), 1);
assert!(variant_attrs.function.is_none(), "That makes no sense");
assert!(
variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
"That makes no sense"
);
}
let mut expr = if !bindings.is_empty() {
let mut expr = if let Some(keyword) = variant_attrs.keyword {
assert!(bindings.is_empty());
let keyword = keyword.to_string();
quote! {
::std::fmt::Write::write_str(dest, #keyword)
}
} else if !bindings.is_empty() {
let mut expr = quote! {};
if variant_attrs.iterable {
assert_eq!(bindings.len(), 1);
@ -123,11 +132,13 @@ struct CssInputAttrs {
#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
struct CssVariantAttrs {
function: Option<Function>,
iterable: bool,
comma: bool,
dimension: bool,
pub struct CssVariantAttrs {
pub function: Option<Function>,
pub iterable: bool,
pub comma: bool,
pub dimension: bool,
pub keyword: Option<Ident>,
pub aliases: Option<String>,
}
#[darling(attributes(css), default)]
@ -136,7 +147,7 @@ struct CssFieldAttrs {
ignore_bound: bool,
}
struct Function {
pub struct Function {
name: Option<Ident>,
}

View File

@ -384,69 +384,12 @@ impl_to_css_for_predefined_type!(::cssparser::UnicodeRange);
#[macro_export]
macro_rules! define_css_keyword_enum {
($name: ident: values { $( $css: expr => $variant: ident),+, }
aliases { $( $alias: expr => $alias_variant: ident ),+, }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),+ ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+, }
aliases { $( $alias: expr => $alias_variant: ident ),* }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+ }
aliases { $( $alias: expr => $alias_variant: ident ),+, }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),+ ]);
};
($name: ident: values { $( $css: expr => $variant: ident),+ }
aliases { $( $alias: expr => $alias_variant: ident ),* }) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]);
};
($name: ident: $( $css: expr => $variant: ident ),+,) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []);
};
($name: ident: $( $css: expr => $variant: ident ),+) => {
__define_css_keyword_enum__add_optional_traits!($name [ $( $css => $variant ),+ ] []);
};
}
#[cfg(feature = "servo")]
#[macro_export]
macro_rules! __define_css_keyword_enum__add_optional_traits {
($name: ident [ $( $css: expr => $variant: ident ),+ ]
[ $( $alias: expr => $alias_variant: ident),* ]) => {
__define_css_keyword_enum__actual! {
$name [ Deserialize, Serialize, MallocSizeOf ]
[ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]
}
};
}
#[cfg(not(feature = "servo"))]
#[macro_export]
macro_rules! __define_css_keyword_enum__add_optional_traits {
($name: ident [ $( $css: expr => $variant: ident ),+ ]
[ $( $alias: expr => $alias_variant: ident),* ]) => {
__define_css_keyword_enum__actual! {
$name [ MallocSizeOf ]
[ $( $css => $variant ),+ ]
[ $( $alias => $alias_variant ),* ]
}
};
}
#[macro_export]
macro_rules! __define_css_keyword_enum__actual {
($name: ident [ $( $derived_trait: ident),* ]
[ $( $css: expr => $variant: ident ),+ ]
[ $( $alias: expr => $alias_variant: ident ),* ]) => {
#[allow(non_camel_case_types, missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq$(, $derived_trait )* )]
(pub enum $name:ident { $($variant:ident = $css:expr,)+ }) => {
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Copy, Debug, Eq, Hash, MallocSizeOf, PartialEq)]
pub enum $name {
$( $variant ),+
$($variant),+
}
impl $name {
@ -458,33 +401,40 @@ macro_rules! __define_css_keyword_enum__actual {
match *input.next()? {
Token::Ident(ref ident) => {
Self::from_ident(ident).map_err(|()| {
location.new_unexpected_token_error(Token::Ident(ident.clone()))
location.new_unexpected_token_error(
Token::Ident(ident.clone()),
)
})
}
ref token => Err(location.new_unexpected_token_error(token.clone()))
ref token => {
Err(location.new_unexpected_token_error(token.clone()))
}
}
}
/// Parse this property from an already-tokenized identifier.
pub fn from_ident(ident: &str) -> Result<$name, ()> {
match_ignore_ascii_case! { ident,
$( $css => Ok($name::$variant), )+
$( $alias => Ok($name::$alias_variant), )*
_ => Err(())
$($css => Ok($name::$variant),)+
_ => Err(())
}
}
}
impl $crate::ToCss for $name {
fn to_css<W>(&self, dest: &mut $crate::CssWriter<W>) -> ::std::fmt::Result
where W: ::std::fmt::Write
fn to_css<W>(
&self,
dest: &mut $crate::CssWriter<W>,
) -> ::std::fmt::Result
where
W: ::std::fmt::Write,
{
match *self {
$( $name::$variant => ::std::fmt::Write::write_str(dest, $css) ),+
}
}
}
}
};
}
/// Helper types for the handling of specified values.

View File

@ -10,14 +10,20 @@ use euclid::TypedSize2D;
#[allow(unused_imports)] use std::ascii::AsciiExt;
use std::fmt::{self, Write};
define_css_keyword_enum!(UserZoom:
"zoom" => Zoom,
"fixed" => Fixed);
define_css_keyword_enum! {
pub enum UserZoom {
Zoom = "zoom",
Fixed = "fixed",
}
}
define_css_keyword_enum!(Orientation:
"auto" => Auto,
"portrait" => Portrait,
"landscape" => Landscape);
define_css_keyword_enum! {
pub enum Orientation {
Auto = "auto",
Portrait = "portrait",
Landscape = "landscape",
}
}
/// A set of viewport descriptors:
///

View File

@ -4727,10 +4727,11 @@ pub extern "C" fn Servo_ParseFontDescriptor(
) -> bool {
use cssparser::UnicodeRange;
use self::nsCSSFontDesc::*;
use style::computed_values::{font_feature_settings, font_stretch, font_style};
use style::computed_values::{font_stretch, font_style};
use style::font_face::{FontDisplay, FontWeight, Source};
use style::properties::longhands::font_language_override;
use style::values::computed::font::FamilyName;
use style::values::specified::font::SpecifiedFontFeatureSettings;
let string = unsafe { (*value).to_string() };
let mut input = ParserInput::new(&string);
@ -4779,7 +4780,7 @@ pub extern "C" fn Servo_ParseFontDescriptor(
eCSSFontDesc_Stretch / font_stretch::T,
eCSSFontDesc_Src / Vec<Source>,
eCSSFontDesc_UnicodeRange / Vec<UnicodeRange>,
eCSSFontDesc_FontFeatureSettings / font_feature_settings::T,
eCSSFontDesc_FontFeatureSettings / SpecifiedFontFeatureSettings,
eCSSFontDesc_FontLanguageOverride / font_language_override::SpecifiedValue,
eCSSFontDesc_Display / FontDisplay,
]

View File

@ -168,16 +168,16 @@ fn border_image_outset_should_return_length_on_length_zero() {
fn test_border_style() {
use style::values::specified::BorderStyle;
assert_roundtrip_with_context!(BorderStyle::parse, r#"none"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"hidden"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"solid"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"double"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"dotted"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"dashed"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"groove"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"ridge"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"inset"#);
assert_roundtrip_with_context!(BorderStyle::parse, r#"outset"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"none"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"hidden"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"solid"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"double"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"dotted"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"dashed"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"groove"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"ridge"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"inset"#);
assert_roundtrip_with_context!(<BorderStyle as Parse>::parse, r#"outset"#);
}
#[test]

View File

@ -3,7 +3,7 @@ use logging;
use logging::LogLevel;
use mozprofile::preferences::Pref;
use mozprofile::profile::Profile;
use mozrunner::runner::{Runner, FirefoxRunner};
use mozrunner::runner::{FirefoxRunner, FirefoxProcess, Runner, RunnerProcess};
use regex::Captures;
use rustc_serialize::base64::FromBase64;
use rustc_serialize::json;
@ -391,7 +391,7 @@ pub struct MarionetteSettings {
pub struct MarionetteHandler {
connection: Mutex<Option<MarionetteConnection>>,
settings: MarionetteSettings,
browser: Option<FirefoxRunner>,
browser: Option<FirefoxProcess>,
current_log_level: Option<LogLevel>,
}
@ -438,45 +438,49 @@ impl MarionetteHandler {
Ok(capabilities)
}
fn start_browser(&mut self, port: u16, mut options: FirefoxOptions) -> WebDriverResult<()> {
let binary = try!(options.binary
fn start_browser(&mut self, port: u16, options: FirefoxOptions) -> WebDriverResult<()> {
let binary = options.binary
.ok_or(WebDriverError::new(ErrorStatus::SessionNotCreated,
"Expected browser binary location, but unable to find \
binary in default location, no \
'moz:firefoxOptions.binary' capability provided, and \
no binary flag set on the command line")));
no binary flag set on the command line"))?;
let custom_profile = options.profile.is_some();
let is_custom_profile = options.profile.is_some();
let mut runner = try!(FirefoxRunner::new(&binary, options.profile.take())
.map_err(|e| WebDriverError::new(ErrorStatus::SessionNotCreated,
e.description().to_owned())));
// double-dashed flags are not accepted on Windows systems
runner.args().push("-marionette".to_owned());
// https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
runner.envs().insert("MOZ_CRASHREPORTER".to_string(), "1".to_string());
runner.envs().insert("MOZ_CRASHREPORTER_NO_REPORT".to_string(), "1".to_string());
runner.envs().insert("MOZ_CRASHREPORTER_SHUTDOWN".to_string(), "1".to_string());
if let Some(args) = options.args.take() {
runner.args().extend(args);
let mut profile = match options.profile {
Some(x) => x,
None => Profile::new(None)?
};
try!(self.set_prefs(port, &mut runner.profile, custom_profile, options.prefs)
self.set_prefs(port, &mut profile, is_custom_profile, options.prefs)
.map_err(|e| {
WebDriverError::new(ErrorStatus::SessionNotCreated,
format!("Failed to set preferences: {}", e))
}));
})?;
try!(runner.start()
let mut runner = FirefoxRunner::new(&binary, profile);
runner
// double-dashed flags are not accepted on Windows systems
.arg("-marionette")
// https://developer.mozilla.org/docs/Environment_variables_affecting_crash_reporting
.env("MOZ_CRASHREPORTER", "1")
.env("MOZ_CRASHREPORTER_NO_REPORT", "1")
.env("MOZ_CRASHREPORTER_SHUTDOWN", "1");
if let Some(args) = options.args.as_ref() {
runner.args(args);
};
let browser_proc = runner.start()
.map_err(|e| {
WebDriverError::new(ErrorStatus::SessionNotCreated,
format!("Failed to start browser {}: {}",
binary.display(), e))
}));
self.browser = Some(runner);
})?;
self.browser = Some(browser_proc);
Ok(())
}
@ -1336,7 +1340,7 @@ impl MarionetteConnection {
}
}
pub fn connect(&mut self, browser: &mut Option<FirefoxRunner>) -> WebDriverResult<()> {
pub fn connect(&mut self, browser: &mut Option<FirefoxProcess>) -> WebDriverResult<()> {
let timeout = 60 * 1000; // ms
let poll_interval = 100; // ms
let poll_attempts = timeout / poll_interval;

View File

@ -48,7 +48,7 @@ class TestMarionette(MarionetteTestCase):
self.assertRaises(socket.timeout, marionette.raise_for_port, timeout=1.0)
self.marionette._send_message("acceptConnections", {"value": True})
marionette.raise_for_port(timeout=1.0)
marionette.raise_for_port(timeout=10.0)
finally:
self.marionette._send_message("acceptConnections", {"value": True})

View File

@ -5,20 +5,51 @@ use std::collections::HashMap;
use std::convert::From;
use std::env;
use std::error::Error;
use std::ffi::{OsStr, OsString};
use std::fmt;
use std::io::{Result as IoResult, Error as IoError, ErrorKind};
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
use std::path::{Path, PathBuf};
use std::process::{Child, Command, Stdio};
use std::process;
use std::process::{Command, Stdio};
pub trait Runner {
fn args(&mut self) -> &mut Vec<String>;
fn build_command(&self, &mut Command);
fn envs(&mut self) -> &mut HashMap<String, String>;
fn is_running(&mut self) -> bool;
fn start(&mut self) -> Result<(), RunnerError>;
type Process;
fn arg<'a, S>(&'a mut self, arg: S) -> &'a mut Self
where
S: AsRef<OsStr>;
fn args<'a, I, S>(&'a mut self, args: I) -> &'a mut Self
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>;
fn env<'a, K, V>(&'a mut self, key: K, value: V) -> &'a mut Self
where
K: AsRef<OsStr>,
V: AsRef<OsStr>;
fn envs<'a, I, K, V>(&'a mut self, envs: I) -> &'a mut Self
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>,
V: AsRef<OsStr>;
fn stdout<'a, T>(&'a mut self, stdout: T) -> &'a mut Self
where
T: Into<Stdio>;
fn stderr<'a, T>(&'a mut self, stderr: T) -> &'a mut Self
where
T: Into<Stdio>;
fn start(self) -> Result<Self::Process, RunnerError>;
}
pub trait RunnerProcess {
fn status(&mut self) -> IoResult<Option<process::ExitStatus>>;
fn stop(&mut self) -> IoResult<Option<process::ExitStatus>>;
fn stop(&mut self) -> IoResult<process::ExitStatus>;
fn is_running(&mut self) -> bool;
}
#[derive(Debug)]
@ -66,94 +97,150 @@ impl From<PrefReaderError> for RunnerError {
}
}
#[derive(Debug)]
pub struct FirefoxProcess {
process: Child,
profile: Profile
}
impl RunnerProcess for FirefoxProcess {
fn status(&mut self) -> IoResult<Option<process::ExitStatus>> {
self.process.try_wait()
}
fn is_running(&mut self) -> bool {
self.status().unwrap().is_none()
}
fn stop(&mut self) -> IoResult<process::ExitStatus> {
self.process.kill()?;
self.process.wait()
}
}
#[derive(Debug)]
pub struct FirefoxRunner {
pub binary: PathBuf,
args: Vec<String>,
envs: HashMap<String, String>,
process: Option<process::Child>,
pub profile: Profile
binary: PathBuf,
profile: Profile,
args: Vec<OsString>,
envs: HashMap<OsString, OsString>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
}
impl FirefoxRunner {
pub fn new(binary: &Path, profile: Option<Profile>) -> IoResult<FirefoxRunner> {
let prof = match profile {
Some(p) => p,
None => try!(Profile::new(None))
};
pub fn new(binary: &Path, profile: Profile) -> FirefoxRunner {
let mut envs: HashMap<OsString, OsString> = HashMap::new();
envs.insert("MOZ_NO_REMOTE".into(), "1".into());
envs.insert("NO_EM_RESTART".into(), "1".into());
let mut envs = HashMap::new();
envs.insert("MOZ_NO_REMOTE".to_string(), "1".to_string());
envs.insert("NO_EM_RESTART".to_string(), "1".to_string());
Ok(FirefoxRunner {
FirefoxRunner {
binary: binary.to_path_buf(),
process: None,
args: Vec::new(),
envs: envs,
profile: prof
})
profile: profile,
args: vec![],
stdout: None,
stderr: None,
}
}
}
impl Runner for FirefoxRunner {
fn args(&mut self) -> &mut Vec<String> {
&mut self.args
type Process = FirefoxProcess;
fn arg<'a, S>(&'a mut self, arg: S) -> &'a mut FirefoxRunner
where
S: AsRef<OsStr>,
{
self.args.push((&arg).into());
self
}
fn build_command(&self, command: &mut Command) {
command
.args(&self.args[..])
.envs(&self.envs);
fn args<'a, I, S>(&'a mut self, args: I) -> &'a mut FirefoxRunner
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
for arg in args {
self.args.push((&arg).into());
}
self
}
fn env<'a, K, V>(&'a mut self, key: K, value: V) -> &'a mut FirefoxRunner
where
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
self.envs.insert((&key).into(), (&value).into());
self
}
fn envs<'a, I, K, V>(&'a mut self, envs: I) -> &'a mut FirefoxRunner
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
for (key, value) in envs {
self.envs.insert((&key).into(), (&value).into());
}
self
}
fn stdout<'a, T>(&'a mut self, stdout: T) -> &'a mut Self
where
T: Into<Stdio>,
{
self.stdout = Some(stdout.into());
self
}
fn stderr<'a, T>(&'a mut self, stderr: T) -> &'a mut Self
where
T: Into<Stdio>,
{
self.stderr = Some(stderr.into());
self
}
fn start(mut self) -> Result<FirefoxProcess, RunnerError> {
let stdout = self.stdout.unwrap_or_else(|| Stdio::inherit());
let stderr = self.stderr.unwrap_or_else(|| Stdio::inherit());
let mut cmd = Command::new(&self.binary);
cmd.args(&self.args[..])
.envs(&self.envs)
.stdout(stdout)
.stderr(stderr);
if !self.args.iter().any(|x| is_profile_arg(x)) {
command.arg("-profile").arg(&self.profile.path);
cmd.arg("-profile").arg(&self.profile.path);
}
command.stdout(Stdio::inherit())
.stderr(Stdio::inherit());
}
cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
fn envs(&mut self) -> &mut HashMap<String, String> {
&mut self.envs
}
fn is_running(&mut self) -> bool {
self.process.is_some() && self.status().unwrap().is_none()
}
fn start(&mut self) -> Result<(), RunnerError> {
let mut cmd = Command::new(&self.binary);
self.build_command(&mut cmd);
let prefs = try!(self.profile.user_prefs());
try!(prefs.write());
self.profile.user_prefs()?.write()?;
info!("Running command: {:?}", cmd);
let process = try!(cmd.spawn());
self.process = Some(process);
Ok(())
}
fn status(&mut self) -> IoResult<Option<process::ExitStatus>> {
self.process.as_mut().map(|p| p.try_wait()).unwrap_or(Ok(None))
}
fn stop(&mut self) -> IoResult<Option<process::ExitStatus>> {
let mut retval = None;
if let Some(ref mut p) = self.process {
try!(p.kill());
retval = Some(try!(p.wait()));
};
Ok(retval)
let process = cmd.spawn()?;
Ok(FirefoxProcess {
process: process,
profile: self.profile
})
}
}
fn parse_arg_name(arg: &str) -> Option<&str> {
fn parse_arg_name<T>(arg: T) -> Option<String>
where
T: AsRef<OsStr>,
{
let arg_os_str: &OsStr = arg.as_ref();
let arg_str = arg_os_str.to_string_lossy();
let mut start = 0;
let mut end = 0;
for (i, c) in arg.chars().enumerate() {
for (i, c) in arg_str.chars().enumerate() {
if i == 0 {
if !platform::arg_prefix_char(c) {
break;
@ -178,7 +265,7 @@ fn parse_arg_name(arg: &str) -> Option<&str> {
}
if start > 0 && end > start {
Some(&arg[start..end])
Some(arg_str[start..end].into())
} else {
None
}
@ -193,28 +280,28 @@ fn name_end_char(c: char) -> bool {
/// Returns a boolean indicating whether a given string
/// contains one of the `-P`, `-Profile` or `-ProfileManager`
/// arguments, respecting the various platform-specific conventions.
pub fn is_profile_arg(arg: &str) -> bool {
pub fn is_profile_arg<T>(arg: T) -> bool
where
T: AsRef<OsStr>,
{
if let Some(name) = parse_arg_name(arg) {
name.eq_ignore_ascii_case("profile") ||
name.eq_ignore_ascii_case("p") ||
name.eq_ignore_ascii_case("profilemanager")
name.eq_ignore_ascii_case("profile") || name.eq_ignore_ascii_case("p")
|| name.eq_ignore_ascii_case("profilemanager")
} else {
false
}
}
fn find_binary(name: &str) -> Option<PathBuf> {
env::var("PATH")
.ok()
.and_then(|path_env| {
for mut path in env::split_paths(&*path_env) {
path.push(name);
if path.exists() {
return Some(path)
}
env::var("PATH").ok().and_then(|path_env| {
for mut path in env::split_paths(&*path_env) {
path.push(name);
if path.exists() {
return Some(path);
}
None
})
}
None
})
}
#[cfg(target_os = "linux")]
@ -239,19 +326,24 @@ pub mod platform {
pub fn firefox_default_path() -> Option<PathBuf> {
if let Some(path) = find_binary("firefox-bin") {
return Some(path)
return Some(path);
}
let home = env::home_dir();
for &(prefix_home, trial_path) in [
(false, "/Applications/Firefox.app/Contents/MacOS/firefox-bin"),
(true, "Applications/Firefox.app/Contents/MacOS/firefox-bin")].iter() {
(
false,
"/Applications/Firefox.app/Contents/MacOS/firefox-bin",
),
(true, "Applications/Firefox.app/Contents/MacOS/firefox-bin"),
].iter()
{
let path = match (home.as_ref(), prefix_home) {
(Some(ref home_dir), true) => home_dir.join(trial_path),
(None, true) => continue,
(_, false) => PathBuf::from(trial_path)
(_, false) => PathBuf::from(trial_path),
};
if path.exists() {
return Some(path)
return Some(path);
}
}
None
@ -274,7 +366,7 @@ pub mod platform {
let opt_path = firefox_registry_path().unwrap_or(None);
if let Some(path) = opt_path {
if path.exists() {
return Some(path)
return Some(path);
}
};
find_binary("firefox.exe")
@ -301,7 +393,7 @@ pub mod platform {
if let Ok(bin_subtree) = mozilla.open_subkey_with_flags(bin_key, KEY_READ) {
let path: Result<String, _> = bin_subtree.get_value("PathToExe");
if let Ok(path) = path {
return Ok(Some(PathBuf::from(path)))
return Ok(Some(PathBuf::from(path)));
}
}
}
@ -331,11 +423,11 @@ pub mod platform {
#[cfg(test)]
mod tests {
use super::{parse_arg_name, is_profile_arg};
use super::{is_profile_arg, parse_arg_name};
fn parse(arg: &str, name: Option<&str>) {
let result = parse_arg_name(arg);
assert_eq!(result, name);
assert_eq!(result, name.map(|x| x.to_string()));
}
#[test]

View File

@ -2000,7 +2000,8 @@ or run without that action (ie: --no-{action})"
yield filter_alert({
"name": "installer size",
"value": installer_size,
"alertThreshold": 1.0,
"alertChangeType": "absolute",
"alertThreshold": (100 * 1024),
"subtests": size_measurements
})

View File

@ -214,10 +214,12 @@ def gl_provider_define(provider):
set_define('MOZ_GL_PROVIDER', gl_provider_define)
@depends(gl_provider, x11)
def gl_default_provider(value, x11):
@depends(gl_provider, wayland, x11)
def gl_default_provider(value, wayland, x11):
if value:
return value
elif wayland:
return 'EGL'
elif x11:
return 'GLX'

View File

@ -47,6 +47,7 @@ const PREF_BLOCKLIST_LASTUPDATETIME = "app.update.lastUpdateTime.blocklist-bac
const PREF_BLOCKLIST_URL = "extensions.blocklist.url";
const PREF_BLOCKLIST_ITEM_URL = "extensions.blocklist.itemURL";
const PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
const PREF_BLOCKLIST_LAST_MODIFIED = "extensions.blocklist.lastModified";
const PREF_BLOCKLIST_LEVEL = "extensions.blocklist.level";
const PREF_BLOCKLIST_PINGCOUNTTOTAL = "extensions.blocklist.pingCountTotal";
const PREF_BLOCKLIST_PINGCOUNTVERSION = "extensions.blocklist.pingCountVersion";
@ -579,7 +580,15 @@ Blocklist.prototype = {
request.open("GET", uri.spec, true);
request.channel.notificationCallbacks = new gCertUtils.BadCertHandler();
request.overrideMimeType("text/xml");
request.setRequestHeader("Cache-Control", "no-cache");
// The server will return a `304 Not Modified` response if the blocklist was
// not changed since last check.
const lastModified = Services.prefs.getCharPref(PREF_BLOCKLIST_LAST_MODIFIED, "");
if (lastModified) {
request.setRequestHeader("If-Modified-Since", lastModified);
} else {
request.setRequestHeader("Cache-Control", "no-cache");
}
request.addEventListener("error", event => this.onXMLError(event));
request.addEventListener("load", event => this.onXMLLoad(event));
@ -607,6 +616,12 @@ Blocklist.prototype = {
LOG("Blocklist::onXMLLoad: " + e);
return;
}
if (request.status == 304) {
LOG("Blocklist::onXMLLoad: up to date.");
return;
}
let responseXML = request.responseXML;
if (!responseXML || responseXML.documentElement.namespaceURI == XMLURI_PARSE_ERROR ||
(request.status != 200 && request.status != 0)) {
@ -614,6 +629,10 @@ Blocklist.prototype = {
return;
}
// Save current blocklist timestamp to pref.
const lastModified = request.getResponseHeader("Last-Modified") || "";
Services.prefs.setCharPref(PREF_BLOCKLIST_LAST_MODIFIED, lastModified);
var oldAddonEntries = this._addonEntries;
var oldPluginEntries = this._pluginEntries;
this._addonEntries = [];