Backed out 17 changesets (bug 1550554, bug 1549593, bug 1551991, bug 1529002) for failing multiple Android tests and Windows 2012 bustages CLOSED TREE

Backed out changeset 3bb3fafa62e2 (bug 1551991)
Backed out changeset e12a979de502 (bug 1551991)
Backed out changeset d81e4aa6bf0c (bug 1551991)
Backed out changeset c354e61f2a34 (bug 1551991)
Backed out changeset 37fd602bebc2 (bug 1551991)
Backed out changeset 6c1f00cc30ca (bug 1551991)
Backed out changeset 8a7a0329bdc3 (bug 1551991)
Backed out changeset 86159475ddd3 (bug 1551991)
Backed out changeset 35f91a9ea82a (bug 1529002)
Backed out changeset 6798155e71dc (bug 1529002)
Backed out changeset b90c2cf5b8c5 (bug 1550554)
Backed out changeset 882ab9868c95 (bug 1550554)
Backed out changeset b28a48e2ed21 (bug 1550554)
Backed out changeset 2c31fe18eefd (bug 1550554)
Backed out changeset 57f2362aa538 (bug 1550554)
Backed out changeset 45f171b26e95 (bug 1550554)
Backed out changeset 2e4b263c9410 (bug 1549593)
This commit is contained in:
Ciure Andrei 2019-05-16 13:17:10 +03:00
parent a309a4b579
commit 00a73f5055
90 changed files with 3669 additions and 2095 deletions

1
Cargo.lock generated
View File

@ -2818,7 +2818,6 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cssparser 0.25.3 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.19.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.21.0",

View File

@ -15,7 +15,7 @@ option(env='CBINDGEN', nargs=1, when=cbindgen_is_needed,
def check_cbindgen_version(cbindgen, fatal=False):
log.debug("trying cbindgen: %s" % cbindgen)
cbindgen_min_version = Version('0.8.7')
cbindgen_min_version = Version('0.8.6')
# cbindgen x.y.z
version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1])

View File

@ -595,49 +595,43 @@ bool AnimationHelper::SampleAnimations(CompositorAnimationStorage* aStorage,
gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4(
const nsTArray<RefPtr<RawServoAnimationValue>>& aValues,
const TransformData& aTransformData) {
// This is a bit silly just to avoid the transform list copy from the
// animation transform list.
auto noneTranslate = StyleTranslate::None();
auto noneRotate = StyleRotate::None();
auto noneScale = StyleScale::None();
const StyleTransform noneTransform;
const StyleTranslate* translate = nullptr;
const StyleRotate* rotate = nullptr;
const StyleScale* scale = nullptr;
const StyleTransform* transform = nullptr;
// FIXME: Bug 1457033: We should convert servo's animation value to matrix
// directly without nsCSSValueSharedList.
// TODO: Bug 1429305: Support compositor animations for motion-path.
RefPtr<nsCSSValueSharedList> transform, translate, rotate, scale;
for (const auto& value : aValues) {
MOZ_ASSERT(value);
nsCSSPropertyID id = Servo_AnimationValue_GetPropertyId(value);
RefPtr<nsCSSValueSharedList> list;
nsCSSPropertyID id = Servo_AnimationValue_GetTransform(value, &list);
switch (id) {
case eCSSProperty_transform:
MOZ_ASSERT(!transform);
transform = Servo_AnimationValue_GetTransform(value);
transform = list.forget();
break;
case eCSSProperty_translate:
MOZ_ASSERT(!translate);
translate = Servo_AnimationValue_GetTranslate(value);
translate = list.forget();
break;
case eCSSProperty_rotate:
MOZ_ASSERT(!rotate);
rotate = Servo_AnimationValue_GetRotate(value);
rotate = list.forget();
break;
case eCSSProperty_scale:
MOZ_ASSERT(!scale);
scale = Servo_AnimationValue_GetScale(value);
scale = list.forget();
break;
default:
MOZ_ASSERT_UNREACHABLE("Unsupported transform-like property");
}
}
RefPtr<nsCSSValueSharedList> individualList =
nsStyleDisplay::GenerateCombinedIndividualTransform(translate, rotate,
scale);
// We expect all our transform data to arrive in device pixels
gfx::Point3D transformOrigin = aTransformData.transformOrigin();
nsDisplayTransform::FrameTransformProperties props(
translate ? *translate : noneTranslate, rotate ? *rotate : noneRotate,
scale ? *scale : noneScale, transform ? *transform : noneTransform,
transformOrigin);
std::move(individualList), std::move(transform), transformOrigin);
return nsDisplayTransform::GetResultingTransformMatrix(
props, aTransformData.origin(), aTransformData.appUnitsPerDevPixel(), 0,

View File

@ -46,6 +46,8 @@
#include "TreeTraversal.h" // for ForEachNode, BreadthFirstSearch
#include "VsyncSource.h"
struct nsCSSValueSharedList;
namespace mozilla {
namespace layers {

View File

@ -169,13 +169,13 @@ static void PrintDisplayItemTo(nsDisplayListBuilder* aBuilder,
}
const auto& willChange = aItem->Frame()->StyleDisplay()->mWillChange;
if (!willChange.features.IsEmpty()) {
if (!willChange.IsEmpty()) {
aStream << " (will-change=";
for (size_t i = 0; i < willChange.features.Length(); i++) {
for (size_t i = 0; i < willChange.Length(); i++) {
if (i > 0) {
aStream << ",";
}
nsDependentAtomString buffer(willChange.features.AsSpan()[i].AsAtom());
nsDependentAtomString buffer(willChange[i]);
aStream << NS_LossyConvertUTF16toASCII(buffer).get();
}
aStream << ")";

View File

@ -4365,23 +4365,19 @@ nsRect nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame,
nsRect nsLayoutUtils::GetTextShadowRectsUnion(
const nsRect& aTextAndDecorationsRect, nsIFrame* aFrame, uint32_t aFlags) {
const nsStyleText* textStyle = aFrame->StyleText();
auto shadows = textStyle->mTextShadow.AsSpan();
if (shadows.IsEmpty()) {
return aTextAndDecorationsRect;
}
if (!textStyle->HasTextShadow()) return aTextAndDecorationsRect;
nsRect resultRect = aTextAndDecorationsRect;
int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
for (auto& shadow : shadows) {
nsMargin blur =
nsContextBoxBlur::GetBlurRadiusMargin(shadow.blur.ToAppUnits(), A2D);
for (uint32_t i = 0; i < textStyle->mTextShadow->Length(); ++i) {
nsCSSShadowItem* shadow = textStyle->mTextShadow->ShadowAt(i);
nsMargin blur = nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D);
if ((aFlags & EXCLUDE_BLUR_SHADOWS) && blur != nsMargin(0, 0, 0, 0))
continue;
nsRect tmpRect(aTextAndDecorationsRect);
tmpRect.MoveBy(
nsPoint(shadow.horizontal.ToAppUnits(), shadow.vertical.ToAppUnits()));
tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
tmpRect.Inflate(blur);
resultRect.UnionRect(resultRect, tmpRect);
@ -6103,18 +6099,15 @@ void nsLayoutUtils::PaintTextShadow(
const nsRect& aDirtyRect, const nscolor& aForegroundColor,
TextShadowCallback aCallback, void* aCallbackData) {
const nsStyleText* textStyle = aFrame->StyleText();
auto shadows = textStyle->mTextShadow.AsSpan();
if (shadows.IsEmpty()) {
return;
}
if (!textStyle->HasTextShadow()) return;
// Text shadow happens with the last value being painted at the back,
// ie. it is painted first.
gfxContext* aDestCtx = aContext;
for (auto& shadow : Reversed(shadows)) {
nsPoint shadowOffset(shadow.horizontal.ToAppUnits(),
shadow.vertical.ToAppUnits());
nscoord blurRadius = std::max(shadow.blur.ToAppUnits(), 0);
for (uint32_t i = textStyle->mTextShadow->Length(); i > 0; --i) {
nsCSSShadowItem* shadowDetails = textStyle->mTextShadow->ShadowAt(i - 1);
nsPoint shadowOffset(shadowDetails->mXOffset, shadowDetails->mYOffset);
nscoord blurRadius = std::max(shadowDetails->mRadius, 0);
nsRect shadowRect(aTextRect);
shadowRect.MoveBy(shadowOffset);
@ -6122,17 +6115,18 @@ void nsLayoutUtils::PaintTextShadow(
nsPresContext* presCtx = aFrame->PresContext();
nsContextBoxBlur contextBoxBlur;
nscolor shadowColor = shadow.color.CalcColor(aForegroundColor);
nscolor shadowColor = shadowDetails->mColor.CalcColor(aForegroundColor);
// Webrender just needs the shadow details
if (auto* textDrawer = aContext->GetTextDrawer()) {
wr::Shadow wrShadow;
wrShadow.offset = {
presCtx->AppUnitsToFloatDevPixels(shadow.horizontal.ToAppUnits()),
presCtx->AppUnitsToFloatDevPixels(shadow.vertical.ToAppUnits())};
presCtx->AppUnitsToFloatDevPixels(shadowDetails->mXOffset),
presCtx->AppUnitsToFloatDevPixels(shadowDetails->mYOffset)};
wrShadow.blur_radius = presCtx->AppUnitsToFloatDevPixels(blurRadius);
wrShadow.blur_radius =
presCtx->AppUnitsToFloatDevPixels(shadowDetails->mRadius);
wrShadow.color = wr::ToColorF(ToDeviceColor(shadowColor));
// Gecko already inflates the bounding rect of text shadows,
@ -8297,8 +8291,8 @@ bool nsLayoutUtils::FontSizeInflationEnabled(nsPresContext* aPresContext) {
/* static */
nsRect nsLayoutUtils::GetBoxShadowRectForFrame(nsIFrame* aFrame,
const nsSize& aFrameSize) {
auto boxShadows = aFrame->StyleEffects()->mBoxShadow.AsSpan();
if (boxShadows.IsEmpty()) {
nsCSSShadowArray* boxShadows = aFrame->StyleEffects()->mBoxShadow;
if (!boxShadows) {
return nsRect();
}
@ -8323,19 +8317,17 @@ nsRect nsLayoutUtils::GetBoxShadowRectForFrame(nsIFrame* aFrame,
nsRect shadows;
int32_t A2D = aFrame->PresContext()->AppUnitsPerDevPixel();
for (auto& shadow : boxShadows) {
for (uint32_t i = 0; i < boxShadows->Length(); ++i) {
nsRect tmpRect = inputRect;
nsCSSShadowItem* shadow = boxShadows->ShadowAt(i);
// inset shadows are never painted outside the frame
if (shadow.inset) {
continue;
}
if (shadow->mInset) continue;
tmpRect.MoveBy(nsPoint(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits()));
tmpRect.Inflate(shadow.spread.ToAppUnits());
tmpRect.Inflate(nsContextBoxBlur::GetBlurRadiusMargin(
shadow.base.blur.ToAppUnits(), A2D));
tmpRect.MoveBy(nsPoint(shadow->mXOffset, shadow->mYOffset));
tmpRect.Inflate(shadow->mSpread);
tmpRect.Inflate(
nsContextBoxBlur::GetBlurRadiusMargin(shadow->mRadius, A2D));
shadows.UnionRect(shadows, tmpRect);
}
return shadows;

View File

@ -37,29 +37,10 @@ nsString nsQuoteNode::Text() {
NS_ASSERTION(mType == StyleContentType::OpenQuote ||
mType == StyleContentType::CloseQuote,
"should only be called when mText should be non-null");
nsString result;
int32_t depth = Depth();
MOZ_ASSERT(depth >= -1);
Span<const StyleQuotePair> quotes =
mPseudoFrame->StyleList()->mQuotes._0.AsSpan();
// Reuse the last pair when the depth is greater than the number of
// pairs of quotes. (Also make 'quotes: none' and close-quote from
// a depth of 0 equivalent for the next test.)
if (depth >= static_cast<int32_t>(quotes.Length())) {
depth = static_cast<int32_t>(quotes.Length()) - 1;
}
if (depth == -1) {
// close-quote from a depth of 0 or 'quotes: none'
return result;
}
const StyleQuotePair& pair = quotes[depth];
const StyleOwnedStr& quote =
mType == StyleContentType::OpenQuote ? pair.opening : pair.closing;
result.Assign(NS_ConvertUTF8toUTF16(quote.AsString()));
Servo_Quotes_GetQuote(mPseudoFrame->StyleList()->mQuotes.get(), Depth(),
mType, &result);
return result;
}

View File

@ -103,8 +103,8 @@ void nsDisplayButtonBoxShadowOuter::Paint(nsDisplayListBuilder* aBuilder,
}
bool nsDisplayButtonBoxShadowOuter::CanBuildWebRenderDisplayItems() {
// FIXME(emilio): Is this right? That doesn't make much sense.
if (mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
if (!shadows) {
return false;
}
@ -159,26 +159,22 @@ bool nsDisplayButtonBoxShadowOuter::CreateWebRenderCommands(
}
}
const Span<const StyleBoxShadow> shadows =
mFrame->StyleEffects()->mBoxShadow.AsSpan();
MOZ_ASSERT(!shadows.IsEmpty());
nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
MOZ_ASSERT(shadows);
for (const StyleBoxShadow& shadow : Reversed(shadows)) {
if (shadow.inset) {
for (uint32_t i = shadows->Length(); i > 0; i--) {
nsCSSShadowItem* shadow = shadows->ShadowAt(i - 1);
if (shadow->mInset) {
continue;
}
float blurRadius =
float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
gfx::Color shadowColor =
nsCSSRendering::GetShadowColor(shadow.base, mFrame, 1.0);
nsCSSRendering::GetShadowColor(shadow, mFrame, 1.0);
LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
nsPoint(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits()),
appUnitsPerDevPixel);
nsPoint(shadow->mXOffset, shadow->mYOffset), appUnitsPerDevPixel);
float spreadRadius =
float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
@ -389,7 +385,7 @@ bool nsDisplayButtonForeground::CreateWebRenderCommands(
nsresult nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
nsDisplayList* aBackground,
nsDisplayList* aForeground) {
if (!mFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
if (mFrame->StyleEffects()->mBoxShadow) {
aBackground->AppendNewToTop<nsDisplayButtonBoxShadowOuter>(aBuilder,
GetFrame());
}

View File

@ -222,7 +222,7 @@ void nsFieldSetFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// empty, we need to paint the outline
if (!(GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) &&
IsVisibleForPainting()) {
if (!StyleEffects()->mBoxShadow.IsEmpty()) {
if (StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowOuter>(
aBuilder, this);
}

View File

@ -1214,10 +1214,8 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
needAnchorSuppression = true;
}
// TODO(emilio): Should this do something about other transform-like
// properties?
if (oldDisp->mPosition != StyleDisplay()->mPosition ||
oldDisp->mTransform != StyleDisplay()->mTransform) {
oldDisp->TransformChanged(*StyleDisplay())) {
needAnchorSuppression = true;
}
}
@ -1642,7 +1640,7 @@ bool nsIFrame::HasOpacityInternal(float aThreshold,
EffectSet* aEffectSet) const {
MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
if (aStyleEffects->mOpacity < aThreshold ||
(aStyleDisplay->mWillChange.bits & StyleWillChangeBits_OPACITY)) {
(aStyleDisplay->mWillChangeBitField & StyleWillChangeBits_OPACITY)) {
return true;
}
@ -2417,8 +2415,8 @@ void nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
return;
}
const auto* effects = StyleEffects();
if (effects->HasBoxShadowWithInset(false)) {
nsCSSShadowArray* shadows = StyleEffects()->mBoxShadow;
if (shadows && shadows->HasShadowWithInset(false)) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowOuter>(aBuilder,
this);
}
@ -2426,7 +2424,7 @@ void nsFrame::DisplayBorderBackgroundOutline(nsDisplayListBuilder* aBuilder,
bool bgIsThemed =
DisplayBackgroundUnconditional(aBuilder, aLists, aForceBackground);
if (effects->HasBoxShadowWithInset(true)) {
if (shadows && shadows->HasShadowWithInset(true)) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowInner>(aBuilder,
this);
}
@ -2872,7 +2870,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
NS_STYLE_POINTER_EVENTS_NONE;
bool opacityItemForEventsAndPluginsOnly = false;
if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
!(disp->mWillChange.bits & StyleWillChangeBits_OPACITY) &&
!(disp->mWillChangeBitField & StyleWillChangeBits_OPACITY) &&
!nsLayoutUtils::HasAnimationOfPropertySet(
this, nsCSSPropertyIDSet::OpacityProperties(), effectSetForOpacity)) {
if (needHitTestInfo || aBuilder->WillComputePluginGeometry()) {
@ -2882,7 +2880,7 @@ void nsIFrame::BuildDisplayListForStackingContext(
}
}
if (disp->mWillChange.bits) {
if (disp->mWillChangeBitField) {
aBuilder->AddToWillChangeBudget(this, GetSize());
}
@ -10606,7 +10604,7 @@ bool nsIFrame::IsStackingContext(const nsStyleDisplay* aStyleDisplay,
nsSVGIntegrationUtils::UsingEffectsForFrame(this) ||
(aIsPositioned && (aStyleDisplay->IsPositionForcingStackingContext() ||
aStylePosition->mZIndex.IsInteger())) ||
(aStyleDisplay->mWillChange.bits &
(aStyleDisplay->mWillChangeBitField &
StyleWillChangeBits_STACKING_CONTEXT) ||
aStyleDisplay->mIsolation != NS_STYLE_ISOLATION_AUTO;
}
@ -10669,7 +10667,7 @@ bool nsIFrame::IsScrolledOutOfView() const {
gfx::Matrix nsIFrame::ComputeWidgetTransform() {
const nsStyleUIReset* uiReset = StyleUIReset();
if (uiReset->mMozWindowTransform.IsNone()) {
if (!uiReset->mSpecifiedWindowTransform) {
return gfx::Matrix();
}
@ -10679,7 +10677,8 @@ gfx::Matrix nsIFrame::ComputeWidgetTransform() {
nsPresContext* presContext = PresContext();
int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
gfx::Matrix4x4 matrix = nsStyleTransformMatrix::ReadTransforms(
uiReset->mMozWindowTransform, refBox, float(appUnitsPerDevPixel));
uiReset->mSpecifiedWindowTransform->mHead, refBox,
float(appUnitsPerDevPixel));
// Apply the -moz-window-transform-origin translation to the matrix.
const StyleTransformOrigin& origin = uiReset->mWindowTransformOrigin;

View File

@ -3455,7 +3455,7 @@ void ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
AppendScrollPartsTo(aBuilder, aLists, createLayersForScrollbars, false);
const nsStyleDisplay* disp = mOuter->StyleDisplay();
if (disp->mWillChange.bits & StyleWillChangeBits_SCROLL) {
if (disp->mWillChangeBitField & StyleWillChangeBits_SCROLL) {
aBuilder->AddToWillChangeBudget(mOuter, GetVisualViewportSize());
}
@ -5417,7 +5417,7 @@ bool ScrollFrameHelper::IsScrollbarOnRight() const {
bool ScrollFrameHelper::IsMaybeScrollingActive() const {
const nsStyleDisplay* disp = mOuter->StyleDisplay();
if (disp->mWillChange.bits & StyleWillChangeBits_SCROLL) {
if (disp->mWillChangeBitField & StyleWillChangeBits_SCROLL) {
return true;
}
@ -5430,7 +5430,7 @@ bool ScrollFrameHelper::IsMaybeScrollingActive() const {
bool ScrollFrameHelper::IsScrollingActive(
nsDisplayListBuilder* aBuilder) const {
const nsStyleDisplay* disp = mOuter->StyleDisplay();
if (disp->mWillChange.bits & StyleWillChangeBits_SCROLL &&
if (disp->mWillChangeBitField & StyleWillChangeBits_SCROLL &&
aBuilder->IsInWillChangeBudget(mOuter, GetVisualViewportSize())) {
return true;
}

View File

@ -353,7 +353,7 @@ class nsTextPaintStyle {
// if this returns false, no text-shadow was specified for the selection
// and the *aShadow parameter was not modified.
bool GetSelectionShadow(Span<const StyleSimpleShadow>* aShadows);
bool GetSelectionShadow(nsCSSShadowArray** aShadow);
nsPresContext* PresContext() const { return mPresContext; }
@ -398,7 +398,8 @@ class nsTextPaintStyle {
nscolor mSelectionTextColor;
nscolor mSelectionBGColor;
RefPtr<ComputedStyle> mSelectionPseudoStyle;
RefPtr<nsCSSShadowArray> mSelectionShadow;
bool mHasSelectionShadow;
// Common data
@ -1821,52 +1822,52 @@ bool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1,
aFrame2->GetParent()->GetContent()) {
// Does aFrame, or any ancestor between it and aAncestor, have a property
// that should inhibit cross-element-boundary shaping on aSide?
auto PreventCrossBoundaryShaping = [](const nsIFrame* aFrame,
const nsIFrame* aAncestor,
Side aSide) {
while (aFrame != aAncestor) {
ComputedStyle* ctx = aFrame->Style();
// According to https://drafts.csswg.org/css-text/#boundary-shaping:
//
// Text shaping must be broken at inline box boundaries when any of
// the following are true for any box whose boundary separates the
// two typographic character units:
//
// 1. Any of margin/border/padding separating the two typographic
// character units in the inline axis is non-zero.
const auto& margin = ctx->StyleMargin()->mMargin.Get(aSide);
if (!margin.ConvertsToLength() ||
margin.AsLengthPercentage().ToLength() != 0) {
return true;
}
const auto& padding = ctx->StylePadding()->mPadding.Get(aSide);
if (!padding.ConvertsToLength() || padding.ToLength() != 0) {
return true;
}
if (ctx->StyleBorder()->GetComputedBorderWidth(aSide) != 0) {
return true;
}
auto PreventCrossBoundaryShaping =
[](const nsIFrame* aFrame, const nsIFrame* aAncestor, Side aSide) {
while (aFrame != aAncestor) {
ComputedStyle* ctx = aFrame->Style();
// According to https://drafts.csswg.org/css-text/#boundary-shaping:
//
// Text shaping must be broken at inline box boundaries when any of
// the following are true for any box whose boundary separates the
// two typographic character units:
//
// 1. Any of margin/border/padding separating the two typographic
// character units in the inline axis is non-zero.
const auto& margin = ctx->StyleMargin()->mMargin.Get(aSide);
if (!margin.ConvertsToLength() ||
margin.AsLengthPercentage().ToLength() != 0) {
return true;
}
const auto& padding = ctx->StylePadding()->mPadding.Get(aSide);
if (!padding.ConvertsToLength() || padding.ToLength() != 0) {
return true;
}
if (ctx->StyleBorder()->GetComputedBorderWidth(aSide) != 0) {
return true;
}
// 2. vertical-align is not baseline.
//
// FIXME: Should this use VerticalAlignEnum()?
const auto& verticalAlign = ctx->StyleDisplay()->mVerticalAlign;
if (!verticalAlign.IsKeyword() ||
verticalAlign.AsKeyword() != StyleVerticalAlignKeyword::Baseline) {
return true;
}
// 2. vertical-align is not baseline.
//
// FIXME: Should this use VerticalAlignEnum()?
const auto& verticalAlign = ctx->StyleDisplay()->mVerticalAlign;
if (!verticalAlign.IsKeyword() ||
verticalAlign.AsKeyword() !=
StyleVerticalAlignKeyword::Baseline) {
return true;
}
// 3. The boundary is a bidi isolation boundary.
const uint8_t unicodeBidi = ctx->StyleTextReset()->mUnicodeBidi;
if (unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE ||
unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE) {
return true;
}
// 3. The boundary is a bidi isolation boundary.
const uint8_t unicodeBidi = ctx->StyleTextReset()->mUnicodeBidi;
if (unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE ||
unicodeBidi == NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE) {
return true;
}
aFrame = aFrame->GetParent();
}
return false;
};
aFrame = aFrame->GetParent();
}
return false;
};
const nsIFrame* ancestor =
nsLayoutUtils::FindNearestCommonAncestorFrame(aFrame1, aFrame2);
@ -2587,7 +2588,8 @@ void BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun,
// The CSS word-break value may change within a word, so we reset it for
// each MappedFlow. The line-breaker will flush its text if the property
// actually changes.
auto wordBreak = mappedFlow->mStartFrame->StyleText()->EffectiveWordBreak();
auto wordBreak =
mappedFlow->mStartFrame->StyleText()->EffectiveWordBreak();
switch (wordBreak) {
case StyleWordBreak::BreakAll:
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_BreakAll);
@ -3786,6 +3788,7 @@ nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
mResolveColors(true),
mSelectionTextColor(NS_RGBA(0, 0, 0, 0)),
mSelectionBGColor(NS_RGBA(0, 0, 0, 0)),
mHasSelectionShadow(false),
mSufficientContrast(0),
mFrameBackgroundColor(NS_RGBA(0, 0, 0, 0)),
mSystemFieldForegroundColor(NS_RGBA(0, 0, 0, 0)),
@ -4059,7 +4062,8 @@ bool nsTextPaintStyle::InitSelectionColorsAndShadow() {
style->GetVisitedDependentColor(&nsStyleBackground::mBackgroundColor);
mSelectionTextColor =
style->GetVisitedDependentColor(&nsStyleText::mWebkitTextFillColor);
mSelectionPseudoStyle = style.forget();
mHasSelectionShadow = true;
mSelectionShadow = style->StyleText()->mTextShadow;
return true;
}
@ -4236,14 +4240,13 @@ bool nsTextPaintStyle::GetSelectionUnderline(nsPresContext* aPresContext,
color != NS_TRANSPARENT && size > 0.0f;
}
bool nsTextPaintStyle::GetSelectionShadow(
Span<const StyleSimpleShadow>* aShadows) {
bool nsTextPaintStyle::GetSelectionShadow(nsCSSShadowArray** aShadow) {
if (!InitSelectionColorsAndShadow()) {
return false;
}
if (mSelectionPseudoStyle) {
*aShadows = mSelectionPseudoStyle->StyleText()->mTextShadow.AsSpan();
if (mHasSelectionShadow) {
*aShadow = mSelectionShadow;
return true;
}
@ -5698,18 +5701,21 @@ bool nsTextFrame::GetSelectionTextColors(SelectionType aSelectionType,
}
/**
* This sets *aShadows to the appropriate shadows, if any, for the given
* type of selection.
* If text-shadow was not specified, *aShadows is left untouched.
* This sets *aShadow to the appropriate shadow, if any, for the given
* type of selection. Returns true if *aShadow was set.
* If text-shadow was not specified, *aShadow is left untouched
* (NOT reset to null), and the function returns false.
*/
static void GetSelectionTextShadow(nsIFrame* aFrame,
static bool GetSelectionTextShadow(nsIFrame* aFrame,
SelectionType aSelectionType,
nsTextPaintStyle& aTextPaintStyle,
Span<const StyleSimpleShadow>* aShadows) {
if (aSelectionType != SelectionType::eNormal) {
return;
nsCSSShadowArray** aShadow) {
switch (aSelectionType) {
case SelectionType::eNormal:
return aTextPaintStyle.GetSelectionShadow(aShadow);
default:
return false;
}
aTextPaintStyle.GetSelectionShadow(aShadows);
}
/**
@ -5840,21 +5846,22 @@ static void AddHyphenToMetrics(nsTextFrame* aTextFrame,
}
void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
const StyleSimpleShadow& aShadowDetails,
nsCSSShadowItem* aShadowDetails,
gfxRect& aBoundingBox, uint32_t aBlurFlags) {
AUTO_PROFILER_LABEL("nsTextFrame::PaintOneShadow", GRAPHICS);
nsPoint shadowOffset(aShadowDetails.horizontal.ToAppUnits(),
aShadowDetails.vertical.ToAppUnits());
nscoord blurRadius = std::max(aShadowDetails.blur.ToAppUnits(), 0);
gfx::Point shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset);
nscoord blurRadius = std::max(aShadowDetails->mRadius, 0);
nscolor shadowColor = aShadowDetails.color.CalcColor(aParams.foregroundColor);
nscolor shadowColor =
aShadowDetails->mColor.CalcColor(aParams.foregroundColor);
if (auto* textDrawer = aParams.context->GetTextDrawer()) {
wr::Shadow wrShadow;
wrShadow.offset = {PresContext()->AppUnitsToFloatDevPixels(shadowOffset.x),
PresContext()->AppUnitsToFloatDevPixels(shadowOffset.y)};
wrShadow.offset = {
PresContext()->AppUnitsToFloatDevPixels(aShadowDetails->mXOffset),
PresContext()->AppUnitsToFloatDevPixels(aShadowDetails->mYOffset)};
wrShadow.blur_radius = PresContext()->AppUnitsToFloatDevPixels(blurRadius);
wrShadow.color = wr::ToColorF(ToDeviceColor(shadowColor));
@ -5884,8 +5891,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
aBoundingBox + gfxPoint(aParams.framePt.x + aParams.leftSideOffset,
aParams.textBaselinePt.y);
}
Point shadowGfxOffset(shadowOffset.x, shadowOffset.y);
shadowGfxRect += gfxPoint(shadowGfxOffset.x, shadowOffset.y);
shadowGfxRect += gfxPoint(shadowOffset.x, shadowOffset.y);
nsRect shadowRect(NSToCoordRound(shadowGfxRect.X()),
NSToCoordRound(shadowGfxRect.Y()),
@ -5911,7 +5917,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
DrawTextParams params(shadowContext);
params.advanceWidth = &advanceWidth;
params.dirtyRect = aParams.dirtyRect;
params.framePt = aParams.framePt + shadowGfxOffset;
params.framePt = aParams.framePt + shadowOffset;
params.provider = aParams.provider;
params.textStyle = &textPaintStyle;
params.textColor =
@ -5921,7 +5927,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
// Multi-color shadow is not allowed, so we use the same color of the text
// color.
params.decorationOverrideColor = &params.textColor;
DrawText(aParams.range, aParams.textBaselinePt + shadowGfxOffset, params);
DrawText(aParams.range, aParams.textBaselinePt + shadowOffset, params);
contextBoxBlur.DoPaint();
aParams.context->Restore();
@ -6075,10 +6081,10 @@ bool nsTextFrame::PaintTextWithSelectionColors(
// Determine what shadow, if any, to draw - either from textStyle
// or from the ::-moz-selection pseudo-class if specified there
Span<const StyleSimpleShadow> shadows = textStyle->mTextShadow.AsSpan();
nsCSSShadowArray* shadow = textStyle->GetTextShadow();
GetSelectionTextShadow(this, selectionType, *aParams.textPaintStyle,
&shadows);
if (!shadows.IsEmpty()) {
&shadow);
if (shadow) {
nscoord startEdge = iOffset;
if (mTextRun->IsInlineReversed()) {
startEdge -=
@ -6088,7 +6094,7 @@ bool nsTextFrame::PaintTextWithSelectionColors(
shadowParams.textBaselinePt = textBaselinePt;
shadowParams.foregroundColor = foreground;
shadowParams.leftSideOffset = startEdge;
PaintShadows(shadows, shadowParams);
PaintShadows(shadow, shadowParams);
}
// Draw text segment
@ -6448,9 +6454,9 @@ bool nsTextFrame::MeasureCharClippedText(
return maxLength != 0;
}
void nsTextFrame::PaintShadows(Span<const StyleSimpleShadow> aShadows,
void nsTextFrame::PaintShadows(nsCSSShadowArray* aShadow,
const PaintShadowParams& aParams) {
if (aShadows.IsEmpty()) {
if (!aShadow) {
return;
}
@ -6491,8 +6497,9 @@ void nsTextFrame::PaintShadows(Span<const StyleSimpleShadow> aShadows,
Swap(shadowMetrics.mBoundingBox.width, shadowMetrics.mBoundingBox.height);
}
for (const auto& shadow : Reversed(aShadows)) {
PaintOneShadow(aParams, shadow, shadowMetrics.mBoundingBox, blurFlags);
for (uint32_t i = aShadow->Length(); i > 0; --i) {
PaintOneShadow(aParams, aShadow->ShadowAt(i - 1),
shadowMetrics.mBoundingBox, blurFlags);
}
}
@ -6602,7 +6609,7 @@ void nsTextFrame::PaintText(const PaintTextParams& aParams,
shadowParams.provider = &provider;
shadowParams.foregroundColor = foregroundColor;
shadowParams.clipEdges = &clipEdges;
PaintShadows(textStyle->mTextShadow.AsSpan(), shadowParams);
PaintShadows(textStyle->mTextShadow, shadowParams);
}
gfxFloat advanceWidth;

View File

@ -676,10 +676,10 @@ class nsTextFrame : public nsFrame {
};
void PaintOneShadow(const PaintShadowParams& aParams,
const mozilla::StyleSimpleShadow& aShadowDetails,
gfxRect& aBoundingBox, uint32_t aBlurFlags);
nsCSSShadowItem* aShadowDetails, gfxRect& aBoundingBox,
uint32_t aBlurFlags);
void PaintShadows(mozilla::Span<const mozilla::StyleSimpleShadow>,
void PaintShadows(nsCSSShadowArray* aShadow,
const PaintShadowParams& aParams);
struct LineDecoration {

View File

@ -264,7 +264,7 @@ void ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent,
static void IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame,
LayerActivity* aActivity) {
const nsStyleDisplay* display = aFrame->StyleDisplay();
if (!display->HasTransformProperty() && !display->HasIndividualTransform() &&
if (!display->mSpecifiedTransform && !display->HasIndividualTransform() &&
!(display->mMotion && display->mMotion->HasPath())) {
// The transform was removed.
aActivity->mPreviousTransformScale = Nothing();
@ -276,9 +276,12 @@ static void IncrementScaleRestyleCountIfNeeded(nsIFrame* aFrame,
// Compute the new scale due to the CSS transform property.
nsStyleTransformMatrix::TransformReferenceBox refBox(aFrame);
Matrix4x4 transform = nsStyleTransformMatrix::ReadTransforms(
display->mTranslate, display->mRotate, display->mScale,
nsLayoutUtils::ResolveMotionPath(aFrame), display->mTransform, refBox,
AppUnitsPerCSSPixel());
display->mIndividualTransform ? display->mIndividualTransform->mHead
: nullptr,
nsLayoutUtils::ResolveMotionPath(aFrame),
display->mSpecifiedTransform ? display->mSpecifiedTransform->mHead
: nullptr,
refBox, AppUnitsPerCSSPixel());
Matrix transform2D;
if (!transform.Is2D(&transform2D)) {
// We don't attempt to handle 3D transforms; just assume the scale changed.
@ -480,14 +483,14 @@ bool ActiveLayerTracker::IsStyleAnimated(
const nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(aFrame);
const nsCSSPropertyIDSet transformSet =
nsCSSPropertyIDSet::TransformLikeProperties();
if ((styleFrame && (styleFrame->StyleDisplay()->mWillChange.bits &
if ((styleFrame && (styleFrame->StyleDisplay()->mWillChangeBitField &
StyleWillChangeBits_TRANSFORM)) &&
aPropertySet.Intersects(transformSet) &&
(!aBuilder ||
aBuilder->IsInWillChangeBudget(aFrame, aFrame->GetSize()))) {
return true;
}
if ((aFrame->StyleDisplay()->mWillChange.bits &
if ((aFrame->StyleDisplay()->mWillChangeBitField &
StyleWillChangeBits_OPACITY) &&
aPropertySet.Intersects(nsCSSPropertyIDSet::OpacityProperties()) &&
(!aBuilder ||

View File

@ -1354,10 +1354,10 @@ bool nsCSSRendering::HasBoxShadowNativeTheme(nsIFrame* aFrame,
return false;
}
gfx::Color nsCSSRendering::GetShadowColor(const StyleSimpleShadow& aShadow,
gfx::Color nsCSSRendering::GetShadowColor(nsCSSShadowItem* aShadow,
nsIFrame* aFrame, float aOpacity) {
// Get the shadow color; if not specified, use the foreground color
nscolor shadowColor = aShadow.color.CalcColor(aFrame);
nscolor shadowColor = aShadow->mColor.CalcColor(aFrame);
Color color = Color::FromABGR(shadowColor);
color.a *= aOpacity;
return color;
@ -1401,10 +1401,8 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
const nsRect& aDirtyRect,
float aOpacity) {
DrawTarget& aDrawTarget = *aRenderingContext.GetDrawTarget();
auto shadows = aForFrame->StyleEffects()->mBoxShadow.AsSpan();
if (shadows.IsEmpty()) {
return;
}
nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
if (!shadows) return;
bool hasBorderRadius;
// mutually exclusive with hasBorderRadius
@ -1451,24 +1449,20 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
}
for (const StyleBoxShadow& shadow : Reversed(shadows)) {
if (shadow.inset) {
continue;
}
for (uint32_t i = shadows->Length(); i > 0; --i) {
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
if (shadowItem->mInset) continue;
nsRect shadowRect = frameRect;
nsPoint shadowOffset(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits());
shadowRect.MoveBy(shadowOffset);
nscoord shadowSpread = shadow.spread.ToAppUnits();
shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
if (!nativeTheme) {
shadowRect.Inflate(shadowSpread);
shadowRect.Inflate(shadowItem->mSpread);
}
// shadowRect won't include the blur, so make an extra rect here that
// includes the blur for use in the even-odd rule below.
nsRect shadowRectPlusBlur = shadowRect;
nscoord blurRadius = shadow.base.blur.ToAppUnits();
nscoord blurRadius = shadowItem->mRadius;
shadowRectPlusBlur.Inflate(
nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, oneDevPixel));
@ -1476,7 +1470,7 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
shadowGfxRectPlusBlur.RoundOut();
MaybeSnapToDevicePixels(shadowGfxRectPlusBlur, aDrawTarget, true);
Color gfxShadowColor = GetShadowColor(shadow.base, aForFrame, aOpacity);
Color gfxShadowColor = GetShadowColor(shadowItem, aForFrame, aOpacity);
if (nativeTheme) {
nsContextBoxBlur blurringArea;
@ -1485,10 +1479,11 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
// to draw the widget into the shadow surface to create a mask.
// We need to ensure that there actually *is* a shadow surface
// and that we're not going to draw directly into aRenderingContext.
gfxContext* shadowContext = blurringArea.Init(
shadowRect, shadowSpread, blurRadius, oneDevPixel, &aRenderingContext,
aDirtyRect, useSkipGfxRect ? &skipGfxRect : nullptr,
nsContextBoxBlur::FORCE_MASK);
gfxContext* shadowContext =
blurringArea.Init(shadowRect, shadowItem->mSpread, blurRadius,
oneDevPixel, &aRenderingContext, aDirtyRect,
useSkipGfxRect ? &skipGfxRect : nullptr,
nsContextBoxBlur::FORCE_MASK);
if (!shadowContext) continue;
MOZ_ASSERT(shadowContext == blurringArea.GetContext());
@ -1509,12 +1504,13 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
// Draw the widget shape
gfxContextMatrixAutoSaveRestore save(shadowContext);
gfxPoint devPixelOffset = nsLayoutUtils::PointToGfxPoint(
shadowOffset, aPresContext->AppUnitsPerDevPixel());
nsPoint(shadowItem->mXOffset, shadowItem->mYOffset),
aPresContext->AppUnitsPerDevPixel());
shadowContext->SetMatrixDouble(
shadowContext->CurrentMatrixDouble().PreTranslate(devPixelOffset));
nsRect nativeRect = aDirtyRect;
nativeRect.MoveBy(-shadowOffset);
nativeRect.MoveBy(-nsPoint(shadowItem->mXOffset, shadowItem->mYOffset));
nativeRect.IntersectRect(frameRect, nativeRect);
aPresContext->GetTheme()->DrawWidgetBackground(shadowContext, aForFrame,
styleDisplay->mAppearance,
@ -1581,7 +1577,7 @@ void nsCSSRendering::PaintBoxShadowOuter(nsPresContext* aPresContext,
RectCornerRadii clipRectRadii;
if (hasBorderRadius) {
Float spreadDistance = Float(shadowSpread / oneDevPixel);
Float spreadDistance = Float(shadowItem->mSpread) / oneDevPixel;
Float borderSizes[4];
@ -1614,11 +1610,8 @@ nsRect nsCSSRendering::GetBoxShadowInnerPaddingRect(nsIFrame* aFrame,
}
bool nsCSSRendering::ShouldPaintBoxShadowInner(nsIFrame* aFrame) {
const Span<const StyleBoxShadow> shadows =
aFrame->StyleEffects()->mBoxShadow.AsSpan();
if (shadows.IsEmpty()) {
return false;
}
nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
if (!shadows) return false;
if (aFrame->IsThemed() && aFrame->GetContent() &&
!nsContentUtils::IsChromeDoc(aFrame->GetContent()->GetComposedDoc())) {
@ -1671,8 +1664,7 @@ void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
return;
}
const Span<const StyleBoxShadow> shadows =
aForFrame->StyleEffects()->mBoxShadow.AsSpan();
nsCSSShadowArray* shadows = aForFrame->StyleEffects()->mBoxShadow;
NS_ASSERTION(
aForFrame->IsFieldSetFrame() || aFrameArea.Size() == aForFrame->GetSize(),
"unexpected size");
@ -1684,15 +1676,14 @@ void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
const nscoord oneDevPixel = aPresContext->DevPixelsToAppUnits(1);
for (const StyleBoxShadow& shadow : Reversed(shadows)) {
if (!shadow.inset) {
continue;
}
for (uint32_t i = shadows->Length(); i > 0; --i) {
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
if (!shadowItem->mInset) continue;
// shadowPaintRect: the area to paint on the temp surface
// shadowClipRect: the area on the temporary surface within shadowPaintRect
// that we will NOT paint in
nscoord blurRadius = shadow.base.blur.ToAppUnits();
nscoord blurRadius = shadowItem->mRadius;
nsMargin blurMargin =
nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, oneDevPixel);
nsRect shadowPaintRect = paddingRect;
@ -1703,13 +1694,12 @@ void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
// up values between zero and one device pixels to one device pixel.
// This way of rounding is symmetric around zero, which makes sense for
// the spread radius.
int32_t spreadDistance = shadow.spread.ToAppUnits() / oneDevPixel;
int32_t spreadDistance = shadowItem->mSpread / oneDevPixel;
nscoord spreadDistanceAppUnits =
aPresContext->DevPixelsToAppUnits(spreadDistance);
nsRect shadowClipRect = paddingRect;
shadowClipRect.MoveBy(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits());
shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
shadowClipRect.Deflate(spreadDistanceAppUnits, spreadDistanceAppUnits);
Rect shadowClipGfxRect = NSRectToRect(shadowClipRect, oneDevPixel);
@ -1764,7 +1754,7 @@ void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
Rect shadowGfxRect = NSRectToRect(paddingRect, oneDevPixel);
shadowGfxRect.Round();
Color shadowColor = GetShadowColor(shadow.base, aForFrame, 1.0);
Color shadowColor = GetShadowColor(shadowItem, aForFrame, 1.0);
aRenderingContext.Save();
// This clips the outside border radius.
@ -1780,8 +1770,8 @@ void nsCSSRendering::PaintBoxShadowInner(nsPresContext* aPresContext,
nsContextBoxBlur insetBoxBlur;
gfxRect destRect =
nsLayoutUtils::RectToGfxRect(shadowPaintRect, oneDevPixel);
Point shadowOffset(shadow.base.horizontal.ToAppUnits() / oneDevPixel,
shadow.base.vertical.ToAppUnits() / oneDevPixel);
Point shadowOffset(shadowItem->mXOffset / oneDevPixel,
shadowItem->mYOffset / oneDevPixel);
insetBoxBlur.InsetBoxBlur(
&aRenderingContext, ToRect(destRect), shadowClipGfxRect, shadowColor,

View File

@ -141,7 +141,7 @@ struct nsCSSRendering {
RectCornerRadii& aOutRadii);
static nsRect GetShadowRect(const nsRect& aFrameArea, bool aNativeTheme,
nsIFrame* aForFrame);
static mozilla::gfx::Color GetShadowColor(const mozilla::StyleSimpleShadow&,
static mozilla::gfx::Color GetShadowColor(nsCSSShadowItem* aShadow,
nsIFrame* aFrame, float aOpacity);
// Returns if the frame has a themed frame.
// aMaybeHasBorderRadius will return false if we can early detect

View File

@ -178,83 +178,106 @@ nsCString ActiveScrolledRoot::ToString(
return std::move(str);
}
static inline CSSAngle MakeCSSAngle(const StyleAngle& aValue) {
return CSSAngle(aValue.ToDegrees(), eCSSUnit_Degree);
static inline CSSAngle MakeCSSAngle(const nsCSSValue& aValue) {
return CSSAngle(aValue.GetAngleValue(), aValue.GetUnit());
}
static Rotate GetRotate(const StyleRotate& aValue) {
static Rotate GetRotate(const nsCSSValue& aValue) {
Rotate result = null_t();
switch (aValue.tag) {
case StyleRotate::Tag::None:
if (aValue.GetUnit() == eCSSUnit_None) {
return result;
}
const nsCSSValue::Array* array = aValue.GetArrayValue();
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_rotate:
result = Rotate(Rotation(MakeCSSAngle(array->Item(1))));
break;
case StyleRotate::Tag::Rotate:
result = Rotate(Rotation(MakeCSSAngle(aValue.AsRotate())));
case eCSSKeyword_rotate3d:
result = Rotate(Rotation3D(
array->Item(1).GetFloatValue(), array->Item(2).GetFloatValue(),
array->Item(3).GetFloatValue(), MakeCSSAngle(array->Item(4))));
break;
case StyleRotate::Tag::Rotate3D: {
const auto& rotate = aValue.AsRotate3D();
result = Rotate(
Rotation3D(rotate._0, rotate._1, rotate._2, MakeCSSAngle(rotate._3)));
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupported rotate");
}
return result;
}
static Scale GetScale(const StyleScale& aValue) {
static Scale GetScale(const nsCSSValue& aValue) {
Scale result(1., 1., 1.);
switch (aValue.tag) {
case StyleScale::Tag::None:
if (aValue.GetUnit() == eCSSUnit_None) {
// Use (1, 1, 1) to replace the none case.
return result;
}
const nsCSSValue::Array* array = aValue.GetArrayValue();
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_scalex:
result.x() = array->Item(1).GetFloatValue();
break;
case StyleScale::Tag::Scale: {
auto& scale = aValue.AsScale();
result.x() = scale._0;
result.y() = scale._1;
case eCSSKeyword_scaley:
result.y() = array->Item(1).GetFloatValue();
break;
}
case StyleScale::Tag::Scale3D: {
auto& scale = aValue.AsScale3D();
result.x() = scale._0;
result.y() = scale._1;
result.z() = scale._2;
case eCSSKeyword_scalez:
result.z() = array->Item(1).GetFloatValue();
break;
case eCSSKeyword_scale:
result.x() = array->Item(1).GetFloatValue();
// scale(x) is shorthand for scale(x, x);
result.y() =
array->Count() == 2 ? result.x() : array->Item(2).GetFloatValue();
break;
case eCSSKeyword_scale3d:
result.x() = array->Item(1).GetFloatValue();
result.y() = array->Item(2).GetFloatValue();
result.z() = array->Item(3).GetFloatValue();
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupported scale");
}
return result;
}
static Translation GetTranslate(
TransformReferenceBox& aRefBox, const LengthPercentage& aX,
const LengthPercentage& aY = LengthPercentage::Zero(),
const Length& aZ = Length{0}) {
Translation result(0, 0, 0);
result.x() = nsStyleTransformMatrix::ProcessTranslatePart(
aX, &aRefBox, &TransformReferenceBox::Width);
result.y() = nsStyleTransformMatrix::ProcessTranslatePart(
aY, &aRefBox, &TransformReferenceBox::Height);
result.z() = aZ.ToCSSPixels();
return result;
}
static Translation GetTranslate(const StyleTranslate& aValue,
static Translation GetTranslate(const nsCSSValue& aValue,
TransformReferenceBox& aRefBox) {
Translation result(0, 0, 0);
switch (aValue.tag) {
case StyleTranslate::Tag::None:
if (aValue.GetUnit() == eCSSUnit_None) {
// Use (0, 0, 0) to replace the none case.
return result;
}
const nsCSSValue::Array* array = aValue.GetArrayValue();
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_translatex:
result.x() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), &aRefBox, &TransformReferenceBox::Width);
break;
case StyleTranslate::Tag::Translate: {
auto& translate = aValue.AsTranslate();
result = GetTranslate(aRefBox, translate._0, translate._1);
case eCSSKeyword_translatey:
result.y() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), &aRefBox, &TransformReferenceBox::Height);
break;
}
case StyleTranslate::Tag::Translate3D: {
auto& translate = aValue.AsTranslate3D();
result = GetTranslate(aRefBox, translate._0, translate._1, translate._2);
case eCSSKeyword_translatez:
result.z() =
nsStyleTransformMatrix::ProcessTranslatePart(array->Item(1), nullptr);
break;
case eCSSKeyword_translate:
result.x() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), &aRefBox, &TransformReferenceBox::Width);
// translate(x) is shorthand for translate(x, 0)
if (array->Count() == 3) {
result.y() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), &aRefBox, &TransformReferenceBox::Height);
}
break;
case eCSSKeyword_translate3d:
result.x() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), &aRefBox, &TransformReferenceBox::Width);
result.y() = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), &aRefBox, &TransformReferenceBox::Height);
result.z() =
nsStyleTransformMatrix::ProcessTranslatePart(array->Item(3), nullptr);
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupported translate");
}
@ -262,170 +285,152 @@ static Translation GetTranslate(const StyleTranslate& aValue,
}
static void AddTransformFunctions(
const StyleTransform& aTransform, TransformReferenceBox& aRefBox,
const nsCSSValueList* aList, mozilla::ComputedStyle* aStyle,
nsPresContext* aPresContext, TransformReferenceBox& aRefBox,
InfallibleTArray<TransformFunction>& aFunctions) {
for (const StyleTransformOperation& op : aTransform.Operations()) {
switch (op.tag) {
case StyleTransformOperation::Tag::RotateX: {
CSSAngle theta = MakeCSSAngle(op.AsRotateX());
if (aList->mValue.GetUnit() == eCSSUnit_None) {
return;
}
for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
const nsCSSValue& currElem = curr->mValue;
NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
"Stream should consist solely of functions!");
nsCSSValue::Array* array = currElem.GetArrayValue();
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_rotatex: {
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationX(theta));
break;
}
case StyleTransformOperation::Tag::RotateY: {
CSSAngle theta = MakeCSSAngle(op.AsRotateY());
case eCSSKeyword_rotatey: {
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationY(theta));
break;
}
case StyleTransformOperation::Tag::RotateZ: {
CSSAngle theta = MakeCSSAngle(op.AsRotateZ());
case eCSSKeyword_rotatez: {
CSSAngle theta = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(RotationZ(theta));
break;
}
case StyleTransformOperation::Tag::Rotate: {
CSSAngle theta = MakeCSSAngle(op.AsRotate());
aFunctions.AppendElement(Rotation(theta));
case eCSSKeyword_rotate:
aFunctions.AppendElement(GetRotate(currElem).get_Rotation());
break;
}
case StyleTransformOperation::Tag::Rotate3D: {
const auto& rotate = op.AsRotate3D();
CSSAngle theta = MakeCSSAngle(rotate._3);
aFunctions.AppendElement(
Rotation3D(rotate._0, rotate._1, rotate._2, theta));
case eCSSKeyword_rotate3d:
aFunctions.AppendElement(GetRotate(currElem).get_Rotation3D());
break;
}
case StyleTransformOperation::Tag::ScaleX: {
aFunctions.AppendElement(Scale(op.AsScaleX(), 1., 1.));
case eCSSKeyword_scalex:
case eCSSKeyword_scaley:
case eCSSKeyword_scalez:
case eCSSKeyword_scale:
case eCSSKeyword_scale3d:
aFunctions.AppendElement(GetScale(currElem));
break;
}
case StyleTransformOperation::Tag::ScaleY: {
aFunctions.AppendElement(Scale(1., op.AsScaleY(), 1.));
case eCSSKeyword_translatex:
case eCSSKeyword_translatey:
case eCSSKeyword_translatez:
case eCSSKeyword_translate:
case eCSSKeyword_translate3d:
aFunctions.AppendElement(GetTranslate(currElem, aRefBox));
break;
}
case StyleTransformOperation::Tag::ScaleZ: {
aFunctions.AppendElement(Scale(1., 1., op.AsScaleZ()));
break;
}
case StyleTransformOperation::Tag::Scale: {
const auto& scale = op.AsScale();
aFunctions.AppendElement(Scale(scale._0, scale._1, 1.));
break;
}
case StyleTransformOperation::Tag::Scale3D: {
const auto& scale = op.AsScale3D();
aFunctions.AppendElement(Scale(scale._0, scale._1, scale._2));
break;
}
case StyleTransformOperation::Tag::TranslateX: {
aFunctions.AppendElement(GetTranslate(aRefBox, op.AsTranslateX()));
break;
}
case StyleTransformOperation::Tag::TranslateY: {
aFunctions.AppendElement(
GetTranslate(aRefBox, LengthPercentage::Zero(), op.AsTranslateY()));
break;
}
case StyleTransformOperation::Tag::TranslateZ: {
aFunctions.AppendElement(GetTranslate(aRefBox, LengthPercentage::Zero(),
LengthPercentage::Zero(),
op.AsTranslateZ()));
break;
}
case StyleTransformOperation::Tag::Translate: {
const auto& translate = op.AsTranslate();
aFunctions.AppendElement(
GetTranslate(aRefBox, translate._0, translate._1));
break;
}
case StyleTransformOperation::Tag::Translate3D: {
const auto& translate = op.AsTranslate3D();
aFunctions.AppendElement(
GetTranslate(aRefBox, translate._0, translate._1, translate._2));
break;
}
case StyleTransformOperation::Tag::SkewX: {
CSSAngle x = MakeCSSAngle(op.AsSkewX());
case eCSSKeyword_skewx: {
CSSAngle x = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(SkewX(x));
break;
}
case StyleTransformOperation::Tag::SkewY: {
CSSAngle y = MakeCSSAngle(op.AsSkewY());
case eCSSKeyword_skewy: {
CSSAngle y = MakeCSSAngle(array->Item(1));
aFunctions.AppendElement(SkewY(y));
break;
}
case StyleTransformOperation::Tag::Skew: {
const auto& skew = op.AsSkew();
aFunctions.AppendElement(
Skew(MakeCSSAngle(skew._0), MakeCSSAngle(skew._1)));
case eCSSKeyword_skew: {
CSSAngle x = MakeCSSAngle(array->Item(1));
// skew(x) is shorthand for skew(x, 0)
CSSAngle y(0.0f, eCSSUnit_Degree);
if (array->Count() == 3) {
y = MakeCSSAngle(array->Item(2));
}
aFunctions.AppendElement(Skew(x, y));
break;
}
case StyleTransformOperation::Tag::Matrix: {
case eCSSKeyword_matrix: {
gfx::Matrix4x4 matrix;
const auto& m = op.AsMatrix();
matrix._11 = m.a;
matrix._12 = m.b;
matrix._11 = array->Item(1).GetFloatValue();
matrix._12 = array->Item(2).GetFloatValue();
matrix._13 = 0;
matrix._14 = 0;
matrix._21 = m.c;
matrix._22 = m.d;
matrix._21 = array->Item(3).GetFloatValue();
matrix._22 = array->Item(4).GetFloatValue();
matrix._23 = 0;
matrix._24 = 0;
matrix._31 = 0;
matrix._32 = 0;
matrix._33 = 1;
matrix._34 = 0;
matrix._41 = m.e;
matrix._42 = m.f;
matrix._41 = ProcessTranslatePart(array->Item(5), &aRefBox,
&TransformReferenceBox::Width);
matrix._42 = ProcessTranslatePart(array->Item(6), &aRefBox,
&TransformReferenceBox::Height);
matrix._43 = 0;
matrix._44 = 1;
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case StyleTransformOperation::Tag::Matrix3D: {
const auto& m = op.AsMatrix3D();
case eCSSKeyword_matrix3d: {
gfx::Matrix4x4 matrix;
matrix._11 = m.m11;
matrix._12 = m.m12;
matrix._13 = m.m13;
matrix._14 = m.m14;
matrix._21 = m.m21;
matrix._22 = m.m22;
matrix._23 = m.m23;
matrix._24 = m.m24;
matrix._31 = m.m31;
matrix._32 = m.m32;
matrix._33 = m.m33;
matrix._34 = m.m34;
matrix._41 = m.m41;
matrix._42 = m.m42;
matrix._43 = m.m43;
matrix._44 = m.m44;
matrix._11 = array->Item(1).GetFloatValue();
matrix._12 = array->Item(2).GetFloatValue();
matrix._13 = array->Item(3).GetFloatValue();
matrix._14 = array->Item(4).GetFloatValue();
matrix._21 = array->Item(5).GetFloatValue();
matrix._22 = array->Item(6).GetFloatValue();
matrix._23 = array->Item(7).GetFloatValue();
matrix._24 = array->Item(8).GetFloatValue();
matrix._31 = array->Item(9).GetFloatValue();
matrix._32 = array->Item(10).GetFloatValue();
matrix._33 = array->Item(11).GetFloatValue();
matrix._34 = array->Item(12).GetFloatValue();
matrix._41 = ProcessTranslatePart(array->Item(13), &aRefBox,
&TransformReferenceBox::Width);
matrix._42 = ProcessTranslatePart(array->Item(14), &aRefBox,
&TransformReferenceBox::Height);
matrix._43 = ProcessTranslatePart(array->Item(15), &aRefBox, nullptr);
matrix._44 = array->Item(16).GetFloatValue();
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case StyleTransformOperation::Tag::InterpolateMatrix: {
case eCSSKeyword_interpolatematrix: {
Matrix4x4 matrix;
nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, op, aRefBox);
nsStyleTransformMatrix::ProcessInterpolateMatrix(matrix, array,
aRefBox);
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case StyleTransformOperation::Tag::AccumulateMatrix: {
case eCSSKeyword_accumulatematrix: {
Matrix4x4 matrix;
nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, op, aRefBox);
nsStyleTransformMatrix::ProcessAccumulateMatrix(matrix, array, aRefBox);
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case StyleTransformOperation::Tag::Perspective: {
aFunctions.AppendElement(Perspective(op.AsPerspective().ToCSSPixels()));
case eCSSKeyword_perspective: {
aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Function not handled yet!");
NS_ERROR("Function not handled yet!");
}
}
}
static void AddTransformFunctions(const nsCSSValueSharedList* aList,
const nsIFrame* aFrame,
TransformReferenceBox& aRefBox,
layers::Animatable& aAnimatable) {
MOZ_ASSERT(aList->mHead);
AddTransformFunctions(aList->mHead, aFrame->Style(), aFrame->PresContext(),
aRefBox, aAnimatable.get_ArrayOfTransformFunction());
}
static TimingFunction ToTimingFunction(
const Maybe<ComputedTimingFunction>& aCTF) {
if (aCTF.isNothing()) {
@ -466,22 +471,34 @@ static void SetAnimatable(nsCSSPropertyID aProperty,
aAnimatable = aAnimationValue.GetOpacity();
break;
case eCSSProperty_rotate: {
aAnimatable = GetRotate(aAnimationValue.GetRotateProperty());
RefPtr<const nsCSSValueSharedList> list =
aAnimationValue.GetTransformList();
MOZ_ASSERT(list && list->mHead && !list->mHead->mNext,
"should have only one nsCSSValueList for rotate");
aAnimatable = GetRotate(list->mHead->mValue);
break;
}
case eCSSProperty_scale: {
aAnimatable = GetScale(aAnimationValue.GetScaleProperty());
RefPtr<const nsCSSValueSharedList> list =
aAnimationValue.GetTransformList();
MOZ_ASSERT(list && list->mHead && !list->mHead->mNext,
"should have only one nsCSSValueList for scale");
aAnimatable = GetScale(list->mHead->mValue);
break;
}
case eCSSProperty_translate: {
aAnimatable =
GetTranslate(aAnimationValue.GetTranslateProperty(), aRefBox);
RefPtr<const nsCSSValueSharedList> list =
aAnimationValue.GetTransformList();
MOZ_ASSERT(list && list->mHead && !list->mHead->mNext,
"should have only one nsCSSValueList for translate");
aAnimatable = GetTranslate(list->mHead->mValue, aRefBox);
break;
}
case eCSSProperty_transform: {
aAnimatable = InfallibleTArray<TransformFunction>();
AddTransformFunctions(aAnimationValue.GetTransformProperty(), aRefBox,
aAnimatable.get_ArrayOfTransformFunction());
RefPtr<const nsCSSValueSharedList> list =
aAnimationValue.GetTransformList();
AddTransformFunctions(list, aFrame, aRefBox, aAnimatable);
break;
}
default:
@ -3724,7 +3741,8 @@ bool nsDisplayBackgroundImage::AppendBackgroundItemsToTop(
const nsStyleBorder* borderStyle = aFrame->StyleBorder();
const nsStyleEffects* effectsStyle = aFrame->StyleEffects();
bool hasInsetShadow = effectsStyle->HasBoxShadowWithInset(true);
bool hasInsetShadow = effectsStyle->mBoxShadow &&
effectsStyle->mBoxShadow->HasShadowWithInset(true);
bool willPaintBorder = aAllowWillPaintBorderOptimization && !isThemed &&
!hasInsetShadow && borderStyle->HasBorder();
@ -5362,8 +5380,8 @@ bool nsDisplayBoxShadowOuter::ComputeVisibility(nsDisplayListBuilder* aBuilder,
}
bool nsDisplayBoxShadowOuter::CanBuildWebRenderDisplayItems() {
auto shadows = mFrame->StyleEffects()->mBoxShadow.AsSpan();
if (shadows.IsEmpty()) {
nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
if (!shadows) {
return false;
}
@ -5418,26 +5436,24 @@ bool nsDisplayBoxShadowOuter::CreateWebRenderCommands(
for (uint32_t i = 0; i < rects.Length(); ++i) {
LayoutDeviceRect clipRect =
LayoutDeviceRect::FromAppUnits(rects[i], appUnitsPerDevPixel);
auto shadows = mFrame->StyleEffects()->mBoxShadow.AsSpan();
MOZ_ASSERT(!shadows.IsEmpty());
nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
MOZ_ASSERT(shadows);
for (auto& shadow : Reversed(shadows)) {
if (shadow.inset) {
for (uint32_t j = shadows->Length(); j > 0; j--) {
nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1);
if (shadow->mInset) {
continue;
}
float blurRadius =
float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
gfx::Color shadowColor =
nsCSSRendering::GetShadowColor(shadow.base, mFrame, mOpacity);
nsCSSRendering::GetShadowColor(shadow, mFrame, mOpacity);
// We don't move the shadow rect here since WR does it for us
// Now translate everything to device pixels.
const nsRect& shadowRect = frameRect;
LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
nsPoint(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits()),
appUnitsPerDevPixel);
nsPoint(shadow->mXOffset, shadow->mYOffset), appUnitsPerDevPixel);
LayoutDeviceRect deviceBox =
LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
@ -5455,8 +5471,7 @@ bool nsDisplayBoxShadowOuter::CreateWebRenderCommands(
LayoutDeviceSize::FromUnknownSize(borderRadii.BottomRight()));
}
float spreadRadius =
float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
aBuilder.PushBoxShadow(deviceBoxRect, deviceClipRect, !BackfaceIsHidden(),
deviceBoxRect, wr::ToLayoutVector2D(shadowOffset),
@ -5519,8 +5534,8 @@ void nsDisplayBoxShadowInner::Paint(nsDisplayListBuilder* aBuilder,
bool nsDisplayBoxShadowInner::CanCreateWebRenderCommands(
nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsPoint& aReferenceOffset) {
auto shadows = aFrame->StyleEffects()->mBoxShadow.AsSpan();
if (shadows.IsEmpty()) {
nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
if (!shadows) {
// Means we don't have to paint anything
return true;
}
@ -5551,14 +5566,15 @@ void nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
AutoTArray<nsRect, 10> rects;
ComputeDisjointRectangles(aVisibleRegion, &rects);
auto shadows = aFrame->StyleEffects()->mBoxShadow.AsSpan();
nsCSSShadowArray* shadows = aFrame->StyleEffects()->mBoxShadow;
for (uint32_t i = 0; i < rects.Length(); ++i) {
LayoutDeviceRect clipRect =
LayoutDeviceRect::FromAppUnits(rects[i], appUnitsPerDevPixel);
for (auto& shadow : Reversed(shadows)) {
if (!shadow.inset) {
for (uint32_t i = shadows->Length(); i > 0; --i) {
nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
if (!shadowItem->mInset) {
continue;
}
@ -5572,15 +5588,14 @@ void nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
LayoutDeviceRect::FromAppUnits(shadowRect, appUnitsPerDevPixel);
wr::LayoutRect deviceClipRect = wr::ToRoundedLayoutRect(clipRect);
Color shadowColor =
nsCSSRendering::GetShadowColor(shadow.base, aFrame, 1.0);
nsCSSRendering::GetShadowColor(shadowItem, aFrame, 1.0);
LayoutDevicePoint shadowOffset = LayoutDevicePoint::FromAppUnits(
nsPoint(shadow.base.horizontal.ToAppUnits(),
shadow.base.vertical.ToAppUnits()),
nsPoint(shadowItem->mXOffset, shadowItem->mYOffset),
appUnitsPerDevPixel);
float blurRadius =
float(shadow.base.blur.ToAppUnits()) / float(appUnitsPerDevPixel);
float(shadowItem->mRadius) / float(appUnitsPerDevPixel);
wr::BorderRadius borderRadius = wr::ToBorderRadius(
LayoutDeviceSize::FromUnknownSize(innerRadii.TopLeft()),
@ -5589,7 +5604,7 @@ void nsDisplayBoxShadowInner::CreateInsetBoxShadowWebRenderCommands(
LayoutDeviceSize::FromUnknownSize(innerRadii.BottomRight()));
// NOTE: Any spread radius > 0 will render nothing. WR Bug.
float spreadRadius =
float(shadow.spread.ToAppUnits()) / float(appUnitsPerDevPixel);
float(shadowItem->mSpread) / float(appUnitsPerDevPixel);
aBuilder.PushBoxShadow(
wr::ToLayoutRect(deviceBoxRect), deviceClipRect,
@ -7733,11 +7748,9 @@ nsDisplayTransform::FrameTransformProperties::FrameTransformProperties(
const nsIFrame* aFrame, float aAppUnitsPerPixel,
const nsRect* aBoundsOverride)
: mFrame(aFrame),
mTranslate(aFrame->StyleDisplay()->mTranslate),
mRotate(aFrame->StyleDisplay()->mRotate),
mScale(aFrame->StyleDisplay()->mScale),
mTransform(aFrame->StyleDisplay()->mTransform),
mIndividualTransformList(aFrame->StyleDisplay()->mIndividualTransform),
mMotion(nsLayoutUtils::ResolveMotionPath(aFrame)),
mTransformList(aFrame->StyleDisplay()->mSpecifiedTransform),
mToTransformOrigin(GetDeltaToTransformOrigin(aFrame, aAppUnitsPerPixel,
aBoundsOverride)) {}
@ -7805,8 +7818,13 @@ Matrix4x4 nsDisplayTransform::GetResultingTransformMatrixInternal(
* still have perspective!) */
if (aProperties.HasTransform()) {
result = nsStyleTransformMatrix::ReadTransforms(
aProperties.mTranslate, aProperties.mRotate, aProperties.mScale,
aProperties.mMotion, aProperties.mTransform, refBox, aAppUnitsPerPixel);
aProperties.mIndividualTransformList
? aProperties.mIndividualTransformList->mHead
: nullptr,
aProperties.mMotion,
aProperties.mTransformList ? aProperties.mTransformList->mHead
: nullptr,
refBox, aAppUnitsPerPixel);
} else if (hasSVGTransforms) {
// Correct the translation components for zoom:
float pixelsPerCSSPx = AppUnitsPerCSSPixel() / aAppUnitsPerPixel;
@ -8943,7 +8961,7 @@ bool nsDisplayText::CanApplyOpacity() const {
nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
const nsStyleText* textStyle = f->StyleText();
if (textStyle->HasTextShadow()) {
if (textStyle->mTextShadow) {
return false;
}
@ -8991,7 +9009,7 @@ bool nsDisplayText::CreateWebRenderCommands(
// view. Also if we're selected we might have some shadows from the
// ::selected and ::inctive-selected pseudo-selectors. So don't do this
// optimization if we have shadows or a selection.
if (!(IsSelected() || f->StyleText()->HasTextShadow())) {
if (!(IsSelected() || f->StyleText()->GetTextShadow())) {
nsRect visible = GetPaintRect();
visible.Inflate(3 * appUnitsPerDevPixel);
bounds = bounds.Intersect(visible);
@ -9922,18 +9940,23 @@ bool nsDisplayFilters::CreateWebRenderCSSFilters(WrFiltersHolder& wrFilters) {
case NS_STYLE_FILTER_DROP_SHADOW: {
float appUnitsPerDevPixel =
mFrame->PresContext()->AppUnitsPerDevPixel();
const StyleSimpleShadow& shadow = filter.GetDropShadow();
nscolor color = shadow.color.CalcColor(mFrame);
nsCSSShadowArray* shadows = filter.GetDropShadow();
if (!shadows || shadows->Length() != 1) {
MOZ_ASSERT_UNREACHABLE(
"Exactly one drop shadow should have been "
"parsed.");
return false;
}
nsCSSShadowItem* shadow = shadows->ShadowAt(0);
nscolor color = shadow->mColor.CalcColor(mFrame);
wr::Shadow wrShadow;
wrShadow.offset = {
NSAppUnitsToFloatPixels(shadow.horizontal.ToAppUnits(),
appUnitsPerDevPixel),
NSAppUnitsToFloatPixels(shadow.vertical.ToAppUnits(),
appUnitsPerDevPixel)};
NSAppUnitsToFloatPixels(shadow->mXOffset, appUnitsPerDevPixel),
NSAppUnitsToFloatPixels(shadow->mYOffset, appUnitsPerDevPixel)};
wrShadow.blur_radius =
NSAppUnitsToFloatPixels(shadow.blur.ToAppUnits(),
appUnitsPerDevPixel);
NSAppUnitsToFloatPixels(shadow->mRadius, appUnitsPerDevPixel);
wrShadow.color = {NS_GET_R(color) / 255.0f, NS_GET_G(color) / 255.0f,
NS_GET_B(color) / 255.0f, NS_GET_A(color) / 255.0f};
auto filterOp = wr::FilterOp::DropShadow(wrShadow);

View File

@ -6879,40 +6879,34 @@ class nsDisplayTransform : public nsDisplayHitTestInfoItem {
float aAppUnitsPerPixel,
Matrix4x4& aOutMatrix);
struct MOZ_STACK_CLASS FrameTransformProperties {
struct FrameTransformProperties {
FrameTransformProperties(const nsIFrame* aFrame, float aAppUnitsPerPixel,
const nsRect* aBoundsOverride);
// This constructor is used on the compositor (for animations).
// FIXME: Bug 1186329: if we want to support compositor animations for
// motion path, we need to update this. For now, let mMotion be Nothing().
FrameTransformProperties(const mozilla::StyleTranslate& aTranslate,
const mozilla::StyleRotate& aRotate,
const mozilla::StyleScale& aScale,
const mozilla::StyleTransform& aTransform,
const Point3D& aToTransformOrigin)
FrameTransformProperties(
RefPtr<const nsCSSValueSharedList>&& aIndividualTransform,
RefPtr<const nsCSSValueSharedList>&& aTransformList,
const Point3D& aToTransformOrigin)
: mFrame(nullptr),
mTranslate(aTranslate),
mRotate(aRotate),
mScale(aScale),
mTransform(aTransform),
mIndividualTransformList(std::move(aIndividualTransform)),
mTransformList(std::move(aTransformList)),
mToTransformOrigin(aToTransformOrigin) {}
bool HasTransform() const {
return !mTranslate.IsNone() || !mRotate.IsNone() || !mScale.IsNone() ||
!mTransform.IsNone() || mMotion.isSome();
return mIndividualTransformList || mTransformList || mMotion.isSome();
}
const nsIFrame* mFrame;
const mozilla::StyleTranslate& mTranslate;
const mozilla::StyleRotate& mRotate;
const mozilla::StyleScale& mScale;
const mozilla::StyleTransform& mTransform;
const RefPtr<const nsCSSValueSharedList> mIndividualTransformList;
const mozilla::Maybe<mozilla::MotionPathData> mMotion;
const RefPtr<const nsCSSValueSharedList> mTransformList;
const Point3D mToTransformOrigin;
};
/**
* Given a frame with the transform property or an SVG transform,
* Given a frame with the -moz-transform property or an SVG transform,
* returns the transformation matrix for that frame.
*
* @param aFrame The frame to get the matrix from.

View File

@ -24,7 +24,10 @@
namespace mozilla {
using AdditiveSymbol = StyleAdditiveSymbol;
struct AdditiveSymbol {
CounterValue weight;
nsString symbol;
};
struct NegativeType {
nsString before, after;
@ -46,7 +49,7 @@ struct PadType {
#define LENGTH_LIMIT 150
static bool GetCyclicCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) {
const nsTArray<nsString>& aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 1, "No symbol available for cyclic counter.");
auto n = aSymbols.Length();
CounterValue index = (aOrdinal - 1) % n;
@ -56,7 +59,7 @@ static bool GetCyclicCounterText(CounterValue aOrdinal, nsAString& aResult,
static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult,
CounterValue aStart,
Span<const nsString> aSymbols) {
const nsTArray<nsString>& aSymbols) {
CounterValue index = aOrdinal - aStart;
if (index >= 0 && index < CounterValue(aSymbols.Length())) {
aResult = aSymbols[index];
@ -67,7 +70,7 @@ static bool GetFixedCounterText(CounterValue aOrdinal, nsAString& aResult,
}
static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) {
const nsTArray<nsString>& aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 1,
"No symbol available for symbolic counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
@ -93,7 +96,7 @@ static bool GetSymbolicCounterText(CounterValue aOrdinal, nsAString& aResult,
}
static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) {
const nsTArray<nsString>& aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for alphabetic counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
if (aOrdinal == 0) {
@ -119,7 +122,7 @@ static bool GetAlphabeticCounterText(CounterValue aOrdinal, nsAString& aResult,
}
static bool GetNumericCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const nsString> aSymbols) {
const nsTArray<nsString>& aSymbols) {
MOZ_ASSERT(aSymbols.Length() >= 2, "Too few symbols for numeric counter.");
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
@ -143,11 +146,11 @@ static bool GetNumericCounterText(CounterValue aOrdinal, nsAString& aResult,
}
static bool GetAdditiveCounterText(CounterValue aOrdinal, nsAString& aResult,
Span<const AdditiveSymbol> aSymbols) {
const nsTArray<AdditiveSymbol>& aSymbols) {
MOZ_ASSERT(aOrdinal >= 0, "Invalid ordinal.");
if (aOrdinal == 0) {
const AdditiveSymbol& last = aSymbols[aSymbols.Length() - 1];
const AdditiveSymbol& last = aSymbols.LastElement();
if (last.weight == 0) {
aResult = last.symbol;
return true;
@ -989,8 +992,14 @@ class CustomCounterStyle final : public CounterStyle {
private:
~CustomCounterStyle() {}
Span<const nsString> GetSymbols();
Span<const AdditiveSymbol> GetAdditiveSymbols();
nsCSSValue GetDesc(nsCSSCounterDesc aDesc) const {
nsCSSValue value;
Servo_CounterStyleRule_GetDescriptor(mRule, aDesc, &value);
return value;
}
const nsTArray<nsString>& GetSymbols();
const nsTArray<AdditiveSymbol>& GetAdditiveSymbols();
// The speak-as values of counter styles may form a loop, and the
// loops may have complex interaction with the loop formed by
@ -1036,8 +1045,8 @@ class CustomCounterStyle final : public CounterStyle {
uint16_t mFlags;
// Fields below will be initialized when necessary.
StyleOwnedSlice<nsString> mSymbols;
StyleOwnedSlice<AdditiveSymbol> mAdditiveSymbols;
nsTArray<nsString> mSymbols;
nsTArray<AdditiveSymbol> mAdditiveSymbols;
NegativeType mNegative;
nsString mPrefix, mSuffix;
PadType mPad;
@ -1093,12 +1102,13 @@ void CustomCounterStyle::GetPrefix(nsAString& aResult) {
if (!(mFlags & FLAG_PREFIX_INITED)) {
mFlags |= FLAG_PREFIX_INITED;
if (!Servo_CounterStyleRule_GetPrefix(mRule, &mPrefix)) {
if (IsExtendsSystem()) {
GetExtends()->GetPrefix(mPrefix);
} else {
mPrefix.Truncate();
}
nsCSSValue value = GetDesc(eCSSCounterDesc_Prefix);
if (value.UnitHasStringValue()) {
value.GetStringValue(mPrefix);
} else if (IsExtendsSystem()) {
GetExtends()->GetPrefix(mPrefix);
} else {
mPrefix.Truncate();
}
}
aResult = mPrefix;
@ -1109,12 +1119,13 @@ void CustomCounterStyle::GetSuffix(nsAString& aResult) {
if (!(mFlags & FLAG_SUFFIX_INITED)) {
mFlags |= FLAG_SUFFIX_INITED;
if (!Servo_CounterStyleRule_GetSuffix(mRule, &mSuffix)) {
if (IsExtendsSystem()) {
GetExtends()->GetSuffix(mSuffix);
} else {
mSuffix.AssignLiteral(u". ");
}
nsCSSValue value = GetDesc(eCSSCounterDesc_Suffix);
if (value.UnitHasStringValue()) {
value.GetStringValue(mSuffix);
} else if (IsExtendsSystem()) {
GetExtends()->GetSuffix(mSuffix);
} else {
mSuffix.AssignLiteral(u". ");
}
}
aResult = mSuffix;
@ -1153,14 +1164,26 @@ bool CustomCounterStyle::IsBullet() {
void CustomCounterStyle::GetNegative(NegativeType& aResult) {
if (!(mFlags & FLAG_NEGATIVE_INITED)) {
mFlags |= FLAG_NEGATIVE_INITED;
if (!Servo_CounterStyleRule_GetNegative(mRule,
&mNegative.before,
&mNegative.after)) {
if (IsExtendsSystem()) {
GetExtends()->GetNegative(mNegative);
} else {
mNegative.before.AssignLiteral(u"-");
nsCSSValue value = GetDesc(eCSSCounterDesc_Negative);
switch (value.GetUnit()) {
case eCSSUnit_Ident:
case eCSSUnit_String:
value.GetStringValue(mNegative.before);
mNegative.after.Truncate();
break;
case eCSSUnit_Pair: {
const nsCSSValuePair& pair = value.GetPairValue();
pair.mXValue.GetStringValue(mNegative.before);
pair.mYValue.GetStringValue(mNegative.after);
break;
}
default: {
if (IsExtendsSystem()) {
GetExtends()->GetNegative(mNegative);
} else {
mNegative.before.AssignLiteral(u"-");
mNegative.after.Truncate();
}
}
}
}
@ -1174,21 +1197,23 @@ static inline bool IsRangeValueInfinite(const nsCSSValue& aValue) {
/* virtual */
bool CustomCounterStyle::IsOrdinalInRange(CounterValue aOrdinal) {
auto inRange = Servo_CounterStyleRule_IsInRange(mRule, aOrdinal);
switch (inRange) {
case StyleIsOrdinalInRange::InRange:
return true;
case StyleIsOrdinalInRange::NotInRange:
return false;
case StyleIsOrdinalInRange::NoOrdinalSpecified:
if (IsExtendsSystem()) {
return GetExtends()->IsOrdinalInRange(aOrdinal);
nsCSSValue value = GetDesc(eCSSCounterDesc_Range);
if (value.GetUnit() == eCSSUnit_PairList) {
for (const nsCSSValuePairList* item = value.GetPairListValue();
item != nullptr; item = item->mNext) {
const nsCSSValue& lowerBound = item->mXValue;
const nsCSSValue& upperBound = item->mYValue;
if ((IsRangeValueInfinite(lowerBound) ||
aOrdinal >= lowerBound.GetIntValue()) &&
(IsRangeValueInfinite(upperBound) ||
aOrdinal <= upperBound.GetIntValue())) {
return true;
}
break;
case StyleIsOrdinalInRange::Auto:
break;
default:
MOZ_ASSERT_UNREACHABLE("Unkown result from IsInRange?");
}
return false;
} else if (IsExtendsSystem() && value.GetUnit() == eCSSUnit_None) {
// Only use the range of extended style when 'range' is not specified.
return GetExtends()->IsOrdinalInRange(aOrdinal);
}
return IsOrdinalInAutoRange(aOrdinal);
}
@ -1217,13 +1242,16 @@ bool CustomCounterStyle::IsOrdinalInAutoRange(CounterValue aOrdinal) {
void CustomCounterStyle::GetPad(PadType& aResult) {
if (!(mFlags & FLAG_PAD_INITED)) {
mFlags |= FLAG_PAD_INITED;
if (!Servo_CounterStyleRule_GetPad(mRule, &mPad.width, &mPad.symbol)) {
if (IsExtendsSystem()) {
GetExtends()->GetPad(mPad);
} else {
mPad.width = 0;
mPad.symbol.Truncate();
}
nsCSSValue value = GetDesc(eCSSCounterDesc_Pad);
if (value.GetUnit() == eCSSUnit_Pair) {
const nsCSSValuePair& pair = value.GetPairValue();
mPad.width = pair.mXValue.GetIntValue();
pair.mYValue.GetStringValue(mPad.symbol);
} else if (IsExtendsSystem()) {
GetExtends()->GetPad(mPad);
} else {
mPad.width = 0;
mPad.symbol.Truncate();
}
}
aResult = mPad;
@ -1299,18 +1327,31 @@ bool CustomCounterStyle::GetInitialCounterText(CounterValue aOrdinal,
}
}
Span<const nsString> CustomCounterStyle::GetSymbols() {
const nsTArray<nsString>& CustomCounterStyle::GetSymbols() {
if (mSymbols.IsEmpty()) {
Servo_CounterStyleRule_GetSymbols(mRule, &mSymbols);
nsCSSValue values = GetDesc(eCSSCounterDesc_Symbols);
for (const nsCSSValueList* item = values.GetListValue(); item;
item = item->mNext) {
nsString* symbol = mSymbols.AppendElement();
item->mValue.GetStringValue(*symbol);
}
mSymbols.Compact();
}
return mSymbols.AsSpan();
return mSymbols;
}
Span<const AdditiveSymbol> CustomCounterStyle::GetAdditiveSymbols() {
const nsTArray<AdditiveSymbol>& CustomCounterStyle::GetAdditiveSymbols() {
if (mAdditiveSymbols.IsEmpty()) {
Servo_CounterStyleRule_GetAdditiveSymbols(mRule, &mAdditiveSymbols);
nsCSSValue values = GetDesc(eCSSCounterDesc_AdditiveSymbols);
for (const nsCSSValuePairList* item = values.GetPairListValue(); item;
item = item->mNext) {
AdditiveSymbol* symbol = mAdditiveSymbols.AppendElement();
symbol->weight = item->mXValue.GetIntValue();
item->mYValue.GetStringValue(symbol->symbol);
}
mAdditiveSymbols.Compact();
}
return mAdditiveSymbols.AsSpan();
return mAdditiveSymbols;
}
// This method is used to provide the computed value for 'auto'.
@ -1338,25 +1379,19 @@ void CustomCounterStyle::ComputeRawSpeakAs(uint8_t& aSpeakAs,
NS_ASSERTION(!(mFlags & FLAG_SPEAKAS_INITED),
"ComputeRawSpeakAs is called with speak-as inited.");
auto speakAs = Servo_CounterStyleRule_GetSpeakAs(mRule);
switch (speakAs.tag) {
case StyleCounterSpeakAs::Tag::Auto:
nsCSSValue value = GetDesc(eCSSCounterDesc_SpeakAs);
switch (value.GetUnit()) {
case eCSSUnit_Auto:
aSpeakAs = GetSpeakAsAutoValue();
break;
case StyleCounterSpeakAs::Tag::Bullets:
aSpeakAs = NS_STYLE_COUNTER_SPEAKAS_BULLETS;
case eCSSUnit_Enumerated:
aSpeakAs = value.GetIntValue();
break;
case StyleCounterSpeakAs::Tag::Numbers:
aSpeakAs = NS_STYLE_COUNTER_SPEAKAS_NUMBERS;
break;
case StyleCounterSpeakAs::Tag::Words:
aSpeakAs = NS_STYLE_COUNTER_SPEAKAS_WORDS;
break;
case StyleCounterSpeakAs::Tag::Ident:
case eCSSUnit_AtomIdent:
aSpeakAs = NS_STYLE_COUNTER_SPEAKAS_OTHER;
aSpeakAsCounter = mManager->ResolveCounterStyle(speakAs.AsIdent());
aSpeakAsCounter = mManager->ResolveCounterStyle(value.GetAtomValue());
break;
case StyleCounterSpeakAs::Tag::None: {
case eCSSUnit_Null: {
if (!IsExtendsSystem()) {
aSpeakAs = GetSpeakAsAutoValue();
} else {

View File

@ -118,7 +118,7 @@ class AnonymousCounterStyle final : public CounterStyle {
bool IsSingleString() const { return mSingleString; }
uint8_t GetSystem() const { return mSystem; }
Span<const nsString> GetSymbols() const { return MakeSpan(mSymbols); }
const nsTArray<nsString>& GetSymbols() const { return mSymbols; }
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AnonymousCounterStyle)

View File

@ -1427,6 +1427,21 @@ void Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen) {
EnsureStyleAutoArrayLength(base, aLen);
}
void Gecko_ClearWillChange(nsStyleDisplay* aDisplay, size_t aLength) {
aDisplay->mWillChange.Clear();
aDisplay->mWillChange.SetCapacity(aLength);
}
void Gecko_AppendWillChange(nsStyleDisplay* aDisplay, nsAtom* aAtom) {
aDisplay->mWillChange.AppendElement(aAtom);
}
void Gecko_CopyWillChangeFrom(nsStyleDisplay* aDest,
const nsStyleDisplay* aSrc) {
aDest->mWillChange.Clear();
aDest->mWillChange.AppendElements(aSrc->mWillChange);
}
enum class KeyframeSearchDirection {
Forwards,
Backwards,
@ -1604,6 +1619,18 @@ void Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* aDst, const nsStyleSVG* aSrc) {
aDst->mStrokeDasharray = aSrc->mStrokeDasharray;
}
void Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* aSvg,
uint32_t aLen) {
aSvg->mContextProps.Clear();
aSvg->mContextProps.SetLength(aLen);
}
void Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst,
const nsStyleSVG* aSrc) {
aDst->mContextProps = aSrc->mContextProps;
aDst->mContextPropsBits = aSrc->mContextPropsBits;
}
URLValue* Gecko_URLValue_Create(StyleStrong<RawServoCssUrlData> aCssUrl,
CORSMode aCORSMode) {
RefPtr<URLValue> url = new URLValue(aCssUrl.Consume(), aCORSMode);
@ -1690,6 +1717,166 @@ NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t aLen) {
RefPtr<nsCSSShadowArray> arr = new (aLen) nsCSSShadowArray(aLen);
return arr.forget().take();
}
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t aLen) {
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
if (aLen == 0) {
return list.forget().take();
}
list->mHead = new nsCSSValueList;
nsCSSValueList* cur = list->mHead;
for (uint32_t i = 0; i < aLen - 1; i++) {
cur->mNext = new nsCSSValueList;
cur = cur->mNext;
}
return list.forget().take();
}
nsCSSValueSharedList* Gecko_NewNoneTransform() {
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
list->mHead = new nsCSSValueList;
list->mHead->mValue.SetNoneValue();
return list.forget().take();
}
void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay* aDisplay) {
aDisplay->GenerateCombinedIndividualTransform();
}
void Gecko_CSSValue_SetNumber(nsCSSValue* aCSSValue, float aNumber) {
aCSSValue->SetFloatValue(aNumber, eCSSUnit_Number);
}
float Gecko_CSSValue_GetNumber(const nsCSSValue* aCSSValue) {
return aCSSValue->GetFloatValue();
}
void Gecko_CSSValue_SetKeyword(nsCSSValue* aCSSValue, nsCSSKeyword aKeyword) {
aCSSValue->SetEnumValue(aKeyword);
}
nsCSSKeyword Gecko_CSSValue_GetKeyword(const nsCSSValue* aCSSValue) {
return aCSSValue->GetKeywordValue();
}
void Gecko_CSSValue_SetPercentage(nsCSSValue* aCSSValue, float aPercent) {
aCSSValue->SetPercentValue(aPercent);
}
float Gecko_CSSValue_GetPercentage(const nsCSSValue* aCSSValue) {
return aCSSValue->GetPercentValue();
}
void Gecko_CSSValue_SetPixelLength(nsCSSValue* aCSSValue, float aLen) {
MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null ||
aCSSValue->GetUnit() == eCSSUnit_Pixel);
aCSSValue->SetFloatValue(aLen, eCSSUnit_Pixel);
}
void Gecko_CSSValue_SetCalc(nsCSSValue* aCSSValue,
nsStyleCoord::CalcValue aCalc) {
aCSSValue->SetCalcValue(aCalc);
}
nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(const nsCSSValue* aCSSValue) {
return aCSSValue->GetCalcValue();
}
void Gecko_CSSValue_SetFunction(nsCSSValue* aCSSValue, int32_t aLen) {
nsCSSValue::Array* arr = nsCSSValue::Array::Create(aLen);
aCSSValue->SetArrayValue(arr, eCSSUnit_Function);
}
void Gecko_CSSValue_SetString(nsCSSValue* aCSSValue, const uint8_t* aString,
uint32_t aLength, nsCSSUnit aUnit) {
MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
nsString string;
nsDependentCSubstring slice(reinterpret_cast<const char*>(aString), aLength);
AppendUTF8toUTF16(slice, string);
aCSSValue->SetStringValue(string, aUnit);
}
void Gecko_CSSValue_SetStringFromAtom(nsCSSValue* aCSSValue, nsAtom* aAtom,
nsCSSUnit aUnit) {
aCSSValue->SetStringValue(nsDependentAtomString(aAtom), aUnit);
}
void Gecko_CSSValue_SetAtomIdent(nsCSSValue* aCSSValue, nsAtom* aAtom) {
aCSSValue->SetAtomIdentValue(already_AddRefed<nsAtom>(aAtom));
}
void Gecko_CSSValue_SetArray(nsCSSValue* aCSSValue, int32_t aLength) {
MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
RefPtr<nsCSSValue::Array> array = nsCSSValue::Array::Create(aLength);
aCSSValue->SetArrayValue(array, eCSSUnit_Array);
}
void Gecko_CSSValue_SetInt(nsCSSValue* aCSSValue, int32_t aInteger,
nsCSSUnit aUnit) {
aCSSValue->SetIntValue(aInteger, aUnit);
}
void Gecko_CSSValue_SetFloat(nsCSSValue* aCSSValue, float aValue,
nsCSSUnit aUnit) {
aCSSValue->SetFloatValue(aValue, aUnit);
}
nsCSSValue* Gecko_CSSValue_GetArrayItem(nsCSSValue* aCSSValue, int32_t aIndex) {
return &aCSSValue->GetArrayValue()->Item(aIndex);
}
const nsCSSValue* Gecko_CSSValue_GetArrayItemConst(const nsCSSValue* aCSSValue,
int32_t aIndex) {
return &aCSSValue->GetArrayValue()->Item(aIndex);
}
void Gecko_CSSValue_SetPair(nsCSSValue* aCSSValue, const nsCSSValue* aXValue,
const nsCSSValue* aYValue) {
MOZ_ASSERT(NS_IsMainThread());
aCSSValue->SetPairValue(*aXValue, *aYValue);
}
void Gecko_CSSValue_SetList(nsCSSValue* aCSSValue, uint32_t aLen) {
MOZ_ASSERT(NS_IsMainThread());
nsCSSValueList* item = aCSSValue->SetListValue();
for (uint32_t i = 1; i < aLen; ++i) {
item->mNext = new nsCSSValueList;
item = item->mNext;
}
}
void Gecko_CSSValue_SetPairList(nsCSSValue* aCSSValue, uint32_t aLen) {
MOZ_ASSERT(NS_IsMainThread());
nsCSSValuePairList* item = aCSSValue->SetPairListValue();
for (uint32_t i = 1; i < aLen; ++i) {
item->mNext = new nsCSSValuePairList;
item = item->mNext;
}
}
void Gecko_CSSValue_InitSharedList(nsCSSValue* aCSSValue, uint32_t aLen) {
MOZ_ASSERT(aLen > 0, "Must create at least one nsCSSValueList (mHead)");
nsCSSValueSharedList* list = new nsCSSValueSharedList;
aCSSValue->SetSharedListValue(list);
list->mHead = new nsCSSValueList;
nsCSSValueList* cur = list->mHead;
for (uint32_t i = 1; i < aLen; ++i) {
cur->mNext = new nsCSSValueList;
cur = cur->mNext;
}
}
void Gecko_CSSValue_Drop(nsCSSValue* aCSSValue) { aCSSValue->~nsCSSValue(); }
void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) {
aFont->mLanguage = dont_AddRef(aAtom);
aFont->mExplicitLanguage = true;
@ -1959,6 +2146,8 @@ void Gecko_AddPropertyToSet(nsCSSPropertyIDSet* aPropertySet,
aPropertySet->AddProperty(aProperty);
}
NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
#define STYLE_STRUCT(name) \
\
void Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr, \

View File

@ -18,6 +18,7 @@
#include "mozilla/EffectCompositor.h"
#include "mozilla/ComputedTimingFunction.h"
#include "mozilla/PreferenceSheet.h"
#include "nsCSSValue.h"
#include "nsStyleStruct.h"
class nsAtom;
@ -468,6 +469,9 @@ void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len,
void Gecko_EnsureStyleAnimationArrayLength(void* array, size_t len);
void Gecko_EnsureStyleTransitionArrayLength(void* array, size_t len);
void Gecko_ClearWillChange(nsStyleDisplay* display, size_t length);
void Gecko_AppendWillChange(nsStyleDisplay* display, nsAtom* atom);
void Gecko_CopyWillChangeFrom(nsStyleDisplay* dest, const nsStyleDisplay* src);
// Searches from the beginning of |keyframes| for a Keyframe object with the
// specified offset and timing function. If none is found, a new Keyframe object
@ -585,6 +589,66 @@ void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len);
nsCSSValueSharedList* Gecko_NewNoneTransform();
void Gecko_StyleDisplay_GenerateCombinedTransform(nsStyleDisplay*);
// Getter for nsCSSValue
nsCSSValue* Gecko_CSSValue_GetArrayItem(nsCSSValue*, int32_t index);
// const version of the above function.
const nsCSSValue* Gecko_CSSValue_GetArrayItemConst(const nsCSSValue*,
int32_t index);
nsCSSKeyword Gecko_CSSValue_GetKeyword(const nsCSSValue*);
float Gecko_CSSValue_GetNumber(const nsCSSValue* css_value);
float Gecko_CSSValue_GetPercentage(const nsCSSValue* css_value);
nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(const nsCSSValue* aCSSValue);
void Gecko_CSSValue_SetNumber(nsCSSValue* css_value, float number);
void Gecko_CSSValue_SetKeyword(nsCSSValue* css_value, nsCSSKeyword keyword);
void Gecko_CSSValue_SetPercentage(nsCSSValue* css_value, float percent);
void Gecko_CSSValue_SetPixelLength(nsCSSValue* aCSSValue, float aLen);
void Gecko_CSSValue_SetCalc(nsCSSValue* css_value,
nsStyleCoord::CalcValue calc);
void Gecko_CSSValue_SetFunction(nsCSSValue* css_value, int32_t len);
void Gecko_CSSValue_SetString(nsCSSValue* css_value, const uint8_t* string,
uint32_t len, nsCSSUnit unit);
void Gecko_CSSValue_SetStringFromAtom(nsCSSValue* css_value, nsAtom* atom,
nsCSSUnit unit);
// Take an addrefed nsAtom and set it to the nsCSSValue
void Gecko_CSSValue_SetAtomIdent(nsCSSValue* css_value, nsAtom* atom);
void Gecko_CSSValue_SetArray(nsCSSValue* css_value, int32_t len);
void Gecko_CSSValue_SetInt(nsCSSValue* css_value, int32_t integer,
nsCSSUnit unit);
void Gecko_CSSValue_SetFloat(nsCSSValue* css_value, float value,
nsCSSUnit unit);
void Gecko_CSSValue_SetPair(nsCSSValue* css_value, const nsCSSValue* xvalue,
const nsCSSValue* yvalue);
void Gecko_CSSValue_SetList(nsCSSValue* css_value, uint32_t len);
void Gecko_CSSValue_SetPairList(nsCSSValue* css_value, uint32_t len);
void Gecko_CSSValue_InitSharedList(nsCSSValue* css_value, uint32_t len);
void Gecko_CSSValue_Drop(nsCSSValue* css_value);
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,

View File

@ -59,6 +59,12 @@ BASIC_RULE_FUNCS(CounterStyle)
#undef BASIC_RULE_FUNCS
#undef BASIC_RULE_FUNCS_WITHOUT_GETTER
// TODO(emilio): Move CounterStyleRule outside of nsCSSValue, then remove this
// while at it.
void Servo_CounterStyleRule_GetDescriptor(const RawServoCounterStyleRule* rule,
nsCSSCounterDesc desc,
nsCSSValue* result);
void Servo_CounterStyleRule_GetDescriptorCssText(
const RawServoCounterStyleRule* rule, nsCSSCounterDesc desc,
nsAString* result);

View File

@ -52,8 +52,6 @@ hide-types = [
".*incompatible_char_type",
# https://github.com/rust-lang/rust-bindgen/issues/1503
"mozilla::StyleTimingFunction.*",
# https://github.com/rust-lang/rust-bindgen/issues/1559
"mozilla::StyleGenericTransformOperation_.*",
]
bitfield-enums = [
"nsChangeHint",
@ -462,7 +460,7 @@ cbindgen-types = [
{ gecko = "StyleContain", servo = "values::computed::Contain" },
{ gecko = "StyleRestyleHint", servo = "invalidation::element::restyle_hints::RestyleHint" },
{ gecko = "StyleTouchAction", servo = "values::computed::TouchAction" },
{ gecko = "StyleWillChange", servo = "values::specified::box_::WillChange" },
{ gecko = "StyleWillChangeBits", servo = "values::specified::box_::WillChangeBits" },
{ gecko = "StyleTextDecorationLine", servo = "values::computed::TextDecorationLine" },
{ gecko = "StyleTextTransform", servo = "values::computed::TextTransform" },
{ gecko = "StyleMozListReversed", servo = "values::computed::MozListReversed" },
@ -482,18 +480,6 @@ cbindgen-types = [
{ gecko = "StyleGenericBasicShape", servo = "values::generics::basic_shape::BasicShape" },
{ gecko = "StyleArcSlice", servo = "style_traits::arc_slice::ArcSlice" },
{ gecko = "StyleForgottenArcSlicePtr", servo = "style_traits::arc_slice::ForgottenArcSlicePtr" },
{ gecko = "StyleOwnedSlice", servo = "style_traits::owned_slice::OwnedSlice" },
{ gecko = "StyleMozContextProperties", servo = "values::specified::svg::MozContextProperties" },
{ gecko = "StyleQuotes", servo = "values::specified::list::Quotes" },
{ gecko = "StyleOwnedStr", servo = "style_traits::owned_str::OwnedStr" },
{ gecko = "StyleGenericBoxShadow", servo = "values::generics::effects::BoxShadow" },
{ gecko = "StyleGenericSimpleShadow", servo = "values::generics::effects::SimpleShadow" },
{ gecko = "StyleGenericTransformOperation", servo = "values::generics::transform::TransformOperation" },
{ gecko = "StyleGenericTransform", servo = "values::generics::transform::Transform" },
{ gecko = "StyleGenericScale", servo = "values::generics::transform::Scale" },
{ gecko = "StyleGenericRotate", servo = "values::generics::transform::Rotate" },
{ gecko = "StyleGenericTranslate", servo = "values::generics::transform::Translate" },
{ gecko = "StyleAngle", servo = "values::computed::Angle" }
]
mapped-generic-types = [

View File

@ -10,55 +10,13 @@
#define mozilla_ServoStyleConstsInlines_h
#include "mozilla/ServoStyleConsts.h"
#include "nsGkAtoms.h"
#include <type_traits>
#include <new>
// TODO(emilio): there are quite a few other implementations scattered around
// that should move here.
namespace mozilla {
template <typename T>
inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther) {
len = aOther.len;
if (!len) {
ptr = (T*)alignof(T);
} else {
ptr = (T*)malloc(len * sizeof(T));
size_t i = 0;
for (const T& elem : aOther.AsSpan()) {
new (ptr + i++) T(elem);
}
}
}
template <typename T>
inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther) {
len = aOther.len;
ptr = aOther.ptr;
aOther.ptr = (T*)alignof(T);
aOther.len = 0;
}
template <typename T>
inline void StyleOwnedSlice<T>::Clear() {
if (!len) {
return;
}
for (size_t i : IntegerRange(len)) {
ptr[i].~T();
}
free(ptr);
ptr = (T*)alignof(T);
len = 0;
}
template <typename T>
inline StyleOwnedSlice<T>::~StyleOwnedSlice() {
Clear();
}
// This code is basically a C++ port of the Arc::clone() implementation in
// servo/components/servo_arc/lib.rs.
static constexpr const size_t kStaticRefcount =
@ -70,11 +28,6 @@ static constexpr const uint32_t kArcSliceCanary = 0xf3f3f3f3;
#define ASSERT_CANARY \
MOZ_DIAGNOSTIC_ASSERT(_0.ptr->data.header.header == kArcSliceCanary, "Uh?");
template <typename T>
inline StyleArcSlice<T>::StyleArcSlice() {
_0.ptr = reinterpret_cast<decltype(_0.ptr)>(Servo_StyleArcSlice_EmptyPtr());
}
template <typename T>
inline StyleArcSlice<T>::StyleArcSlice(const StyleArcSlice& aOther) {
MOZ_DIAGNOSTIC_ASSERT(aOther._0.ptr);
@ -102,12 +55,6 @@ inline size_t StyleArcSlice<T>::Length() const {
return _0.ptr->data.header.length;
}
template <typename T>
inline bool StyleArcSlice<T>::IsEmpty() const {
ASSERT_CANARY
return Length() == 0;
}
template <typename T>
inline Span<const T> StyleArcSlice<T>::AsSpan() const {
ASSERT_CANARY
@ -144,53 +91,6 @@ inline StyleArcSlice<T>::~StyleArcSlice() {
#undef ASSERT_CANARY
inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
inline nsAtom* StyleAtom::AsAtom() const {
if (IsStatic()) {
return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[(_0 & ~1) >> 1]);
}
return reinterpret_cast<nsAtom*>(_0);
}
inline StyleAtom::~StyleAtom() {
if (!IsStatic()) {
AsAtom()->Release();
}
}
inline StyleAtom::StyleAtom(const StyleAtom& aOther) : _0(aOther._0) {
if (!IsStatic()) {
reinterpret_cast<nsAtom*>(_0)->AddRef();
}
}
inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); }
inline nsDependentCSubstring StyleOwnedStr::AsString() const {
Span<const uint8_t> s = _0.AsSpan();
return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()),
s.Length());
}
template <typename T>
inline Span<const T> StyleGenericTransform<T>::Operations() const {
return _0.AsSpan();
}
template <typename T>
inline bool StyleGenericTransform<T>::IsNone() const {
return Operations().IsEmpty();
}
inline StyleAngle StyleAngle::Zero() { return {0.0f}; }
inline float StyleAngle::ToDegrees() const { return _0; }
inline double StyleAngle::ToRadians() const {
return double(ToDegrees()) * M_PI / 180.0;
}
} // namespace mozilla
#endif

View File

@ -42,107 +42,196 @@ using nsStyleTransformMatrix::Decompose2DMatrix;
using nsStyleTransformMatrix::Decompose3DMatrix;
using nsStyleTransformMatrix::ShearType;
// TODO(emilio): Remove angle unit in a followup, should always be degrees.
static inline StyleAngle GetCSSAngle(const layers::CSSAngle& aAngle) {
if (aAngle.unit() != eCSSUnit_Degree) {
NS_ERROR("Bogus animation from IPC");
return StyleAngle{0.0};
}
return StyleAngle{aAngle.value()};
}
static StyleTransformOperation OperationFromLayers(
const layers::TransformFunction& aFunction) {
switch (aFunction.type()) {
case layers::TransformFunction::TRotationX: {
const layers::CSSAngle& angle = aFunction.get_RotationX().angle();
return StyleTransformOperation::RotateX(GetCSSAngle(angle));
}
case layers::TransformFunction::TRotationY: {
const layers::CSSAngle& angle = aFunction.get_RotationY().angle();
return StyleTransformOperation::RotateY(GetCSSAngle(angle));
}
case layers::TransformFunction::TRotationZ: {
const layers::CSSAngle& angle = aFunction.get_RotationZ().angle();
return StyleTransformOperation::RotateZ(GetCSSAngle(angle));
}
case layers::TransformFunction::TRotation: {
const layers::CSSAngle& angle = aFunction.get_Rotation().angle();
return StyleTransformOperation::Rotate(GetCSSAngle(angle));
}
case layers::TransformFunction::TRotation3D: {
float x = aFunction.get_Rotation3D().x();
float y = aFunction.get_Rotation3D().y();
float z = aFunction.get_Rotation3D().z();
const layers::CSSAngle& angle = aFunction.get_Rotation3D().angle();
return StyleTransformOperation::Rotate3D(x, y, z, GetCSSAngle(angle));
}
case layers::TransformFunction::TScale: {
float x = aFunction.get_Scale().x();
float y = aFunction.get_Scale().y();
float z = aFunction.get_Scale().z();
return StyleTransformOperation::Scale3D(x, y, z);
}
case layers::TransformFunction::TTranslation: {
float x = aFunction.get_Translation().x();
float y = aFunction.get_Translation().y();
float z = aFunction.get_Translation().z();
return StyleTransformOperation::Translate3D(
LengthPercentage::FromPixels(x), LengthPercentage::FromPixels(y),
Length{z});
}
case layers::TransformFunction::TSkewX: {
const layers::CSSAngle& x = aFunction.get_SkewX().x();
return StyleTransformOperation::SkewX(GetCSSAngle(x));
}
case layers::TransformFunction::TSkewY: {
const layers::CSSAngle& y = aFunction.get_SkewY().y();
return StyleTransformOperation::SkewY(GetCSSAngle(y));
}
case layers::TransformFunction::TSkew: {
const layers::CSSAngle& x = aFunction.get_Skew().x();
const layers::CSSAngle& y = aFunction.get_Skew().y();
return StyleTransformOperation::Skew(GetCSSAngle(x), GetCSSAngle(y));
}
case layers::TransformFunction::TTransformMatrix: {
const gfx::Matrix4x4& matrix = aFunction.get_TransformMatrix().value();
return StyleTransformOperation::Matrix3D({
matrix._11,
matrix._12,
matrix._13,
matrix._14,
matrix._21,
matrix._22,
matrix._23,
matrix._24,
matrix._31,
matrix._32,
matrix._33,
matrix._34,
matrix._41,
matrix._42,
matrix._43,
matrix._44,
});
}
case layers::TransformFunction::TPerspective: {
float perspective = aFunction.get_Perspective().value();
return StyleTransformOperation::Perspective(Length{perspective});
}
static already_AddRefed<nsCSSValue::Array> AppendFunction(
nsCSSKeyword aTransformFunction) {
uint32_t nargs;
switch (aTransformFunction) {
case eCSSKeyword_matrix3d:
nargs = 16;
break;
case eCSSKeyword_matrix:
nargs = 6;
break;
case eCSSKeyword_rotate3d:
nargs = 4;
break;
case eCSSKeyword_interpolatematrix:
case eCSSKeyword_accumulatematrix:
case eCSSKeyword_translate3d:
case eCSSKeyword_scale3d:
nargs = 3;
break;
case eCSSKeyword_translate:
case eCSSKeyword_skew:
case eCSSKeyword_scale:
nargs = 2;
break;
default:
MOZ_ASSERT_UNREACHABLE("All functions should be implemented?");
return StyleTransformOperation::TranslateX(LengthPercentage::Zero());
NS_ERROR("must be a transform function");
MOZ_FALLTHROUGH;
case eCSSKeyword_translatex:
case eCSSKeyword_translatey:
case eCSSKeyword_translatez:
case eCSSKeyword_scalex:
case eCSSKeyword_scaley:
case eCSSKeyword_scalez:
case eCSSKeyword_skewx:
case eCSSKeyword_skewy:
case eCSSKeyword_rotate:
case eCSSKeyword_rotatex:
case eCSSKeyword_rotatey:
case eCSSKeyword_rotatez:
case eCSSKeyword_perspective:
nargs = 1;
break;
}
RefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(nargs + 1);
arr->Item(0).SetIntValue(aTransformFunction, eCSSUnit_Enumerated);
return arr.forget();
}
static nsTArray<StyleTransformOperation> CreateTransformList(
const nsTArray<layers::TransformFunction>& aFunctions) {
nsTArray<StyleTransformOperation> result;
result.SetCapacity(aFunctions.Length());
for (const layers::TransformFunction& function : aFunctions) {
result.AppendElement(OperationFromLayers(function));
static already_AddRefed<nsCSSValue::Array> AppendTransformFunction(
nsCSSKeyword aTransformFunction, nsCSSValueList**& aListTail) {
RefPtr<nsCSSValue::Array> arr = AppendFunction(aTransformFunction);
nsCSSValueList* item = new nsCSSValueList;
item->mValue.SetArrayValue(arr, eCSSUnit_Function);
*aListTail = item;
aListTail = &item->mNext;
return arr.forget();
}
struct BogusAnimation {};
static inline Result<Ok, BogusAnimation> SetCSSAngle(
const layers::CSSAngle& aAngle, nsCSSValue& aValue) {
aValue.SetFloatValue(aAngle.value(), nsCSSUnit(aAngle.unit()));
if (!aValue.IsAngularUnit()) {
NS_ERROR("Bogus animation from IPC");
return Err(BogusAnimation{});
}
return result;
return Ok();
}
static Result<nsCSSValueSharedList*, BogusAnimation> CreateCSSValueList(
const InfallibleTArray<layers::TransformFunction>& aFunctions) {
nsAutoPtr<nsCSSValueList> result;
nsCSSValueList** resultTail = getter_Transfers(result);
for (const layers::TransformFunction& function : aFunctions) {
RefPtr<nsCSSValue::Array> arr;
switch (function.type()) {
case layers::TransformFunction::TRotationX: {
const layers::CSSAngle& angle = function.get_RotationX().angle();
arr = AppendTransformFunction(eCSSKeyword_rotatex, resultTail);
MOZ_TRY(SetCSSAngle(angle, arr->Item(1)));
break;
}
case layers::TransformFunction::TRotationY: {
const layers::CSSAngle& angle = function.get_RotationY().angle();
arr = AppendTransformFunction(eCSSKeyword_rotatey, resultTail);
MOZ_TRY(SetCSSAngle(angle, arr->Item(1)));
break;
}
case layers::TransformFunction::TRotationZ: {
const layers::CSSAngle& angle = function.get_RotationZ().angle();
arr = AppendTransformFunction(eCSSKeyword_rotatez, resultTail);
MOZ_TRY(SetCSSAngle(angle, arr->Item(1)));
break;
}
case layers::TransformFunction::TRotation: {
const layers::CSSAngle& angle = function.get_Rotation().angle();
arr = AppendTransformFunction(eCSSKeyword_rotate, resultTail);
MOZ_TRY(SetCSSAngle(angle, arr->Item(1)));
break;
}
case layers::TransformFunction::TRotation3D: {
float x = function.get_Rotation3D().x();
float y = function.get_Rotation3D().y();
float z = function.get_Rotation3D().z();
const layers::CSSAngle& angle = function.get_Rotation3D().angle();
arr = AppendTransformFunction(eCSSKeyword_rotate3d, resultTail);
arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
MOZ_TRY(SetCSSAngle(angle, arr->Item(4)));
break;
}
case layers::TransformFunction::TScale: {
arr = AppendTransformFunction(eCSSKeyword_scale3d, resultTail);
arr->Item(1).SetFloatValue(function.get_Scale().x(), eCSSUnit_Number);
arr->Item(2).SetFloatValue(function.get_Scale().y(), eCSSUnit_Number);
arr->Item(3).SetFloatValue(function.get_Scale().z(), eCSSUnit_Number);
break;
}
case layers::TransformFunction::TTranslation: {
arr = AppendTransformFunction(eCSSKeyword_translate3d, resultTail);
arr->Item(1).SetFloatValue(function.get_Translation().x(),
eCSSUnit_Pixel);
arr->Item(2).SetFloatValue(function.get_Translation().y(),
eCSSUnit_Pixel);
arr->Item(3).SetFloatValue(function.get_Translation().z(),
eCSSUnit_Pixel);
break;
}
case layers::TransformFunction::TSkewX: {
const layers::CSSAngle& x = function.get_SkewX().x();
arr = AppendTransformFunction(eCSSKeyword_skewx, resultTail);
MOZ_TRY(SetCSSAngle(x, arr->Item(1)));
break;
}
case layers::TransformFunction::TSkewY: {
const layers::CSSAngle& y = function.get_SkewY().y();
arr = AppendTransformFunction(eCSSKeyword_skewy, resultTail);
MOZ_TRY(SetCSSAngle(y, arr->Item(1)));
break;
}
case layers::TransformFunction::TSkew: {
const layers::CSSAngle& x = function.get_Skew().x();
const layers::CSSAngle& y = function.get_Skew().y();
arr = AppendTransformFunction(eCSSKeyword_skew, resultTail);
MOZ_TRY(SetCSSAngle(x, arr->Item(1)));
MOZ_TRY(SetCSSAngle(y, arr->Item(2)));
break;
}
case layers::TransformFunction::TTransformMatrix: {
arr = AppendTransformFunction(eCSSKeyword_matrix3d, resultTail);
const gfx::Matrix4x4& matrix = function.get_TransformMatrix().value();
arr->Item(1).SetFloatValue(matrix._11, eCSSUnit_Number);
arr->Item(2).SetFloatValue(matrix._12, eCSSUnit_Number);
arr->Item(3).SetFloatValue(matrix._13, eCSSUnit_Number);
arr->Item(4).SetFloatValue(matrix._14, eCSSUnit_Number);
arr->Item(5).SetFloatValue(matrix._21, eCSSUnit_Number);
arr->Item(6).SetFloatValue(matrix._22, eCSSUnit_Number);
arr->Item(7).SetFloatValue(matrix._23, eCSSUnit_Number);
arr->Item(8).SetFloatValue(matrix._24, eCSSUnit_Number);
arr->Item(9).SetFloatValue(matrix._31, eCSSUnit_Number);
arr->Item(10).SetFloatValue(matrix._32, eCSSUnit_Number);
arr->Item(11).SetFloatValue(matrix._33, eCSSUnit_Number);
arr->Item(12).SetFloatValue(matrix._34, eCSSUnit_Number);
arr->Item(13).SetFloatValue(matrix._41, eCSSUnit_Number);
arr->Item(14).SetFloatValue(matrix._42, eCSSUnit_Number);
arr->Item(15).SetFloatValue(matrix._43, eCSSUnit_Number);
arr->Item(16).SetFloatValue(matrix._44, eCSSUnit_Number);
break;
}
case layers::TransformFunction::TPerspective: {
float perspective = function.get_Perspective().value();
arr = AppendTransformFunction(eCSSKeyword_perspective, resultTail);
arr->Item(1).SetFloatValue(perspective, eCSSUnit_Pixel);
break;
}
default:
NS_ASSERTION(false, "All functions should be implemented?");
}
}
if (aFunctions.Length() == 0) {
result = new nsCSSValueList();
result->mValue.SetNoneValue();
}
return new nsCSSValueSharedList(result.forget());
}
// AnimationValue Implementation
@ -171,66 +260,17 @@ nscolor AnimationValue::GetColor(nscolor aForegroundColor) const {
return Servo_AnimationValue_GetColor(mServo, aForegroundColor);
}
const StyleTranslate& AnimationValue::GetTranslateProperty() const {
already_AddRefed<const nsCSSValueSharedList> AnimationValue::GetTransformList()
const {
MOZ_ASSERT(mServo);
return *Servo_AnimationValue_GetTranslate(mServo);
}
const StyleRotate& AnimationValue::GetRotateProperty() const {
MOZ_ASSERT(mServo);
return *Servo_AnimationValue_GetRotate(mServo);
}
const StyleScale& AnimationValue::GetScaleProperty() const {
MOZ_ASSERT(mServo);
return *Servo_AnimationValue_GetScale(mServo);
}
const StyleTransform& AnimationValue::GetTransformProperty() const {
MOZ_ASSERT(mServo);
return *Servo_AnimationValue_GetTransform(mServo);
RefPtr<nsCSSValueSharedList> transform;
Servo_AnimationValue_GetTransform(mServo, &transform);
return transform.forget();
}
Size AnimationValue::GetScaleValue(const nsIFrame* aFrame) const {
using namespace nsStyleTransformMatrix;
const StyleTranslate* translate = nullptr;
const StyleRotate* rotate = nullptr;
const StyleScale* scale = nullptr;
const StyleTransform* transform = nullptr;
switch (Servo_AnimationValue_GetPropertyId(mServo)) {
case eCSSProperty_scale:
scale = &GetScaleProperty();
break;
case eCSSProperty_translate:
translate = &GetTranslateProperty();
break;
case eCSSProperty_rotate:
rotate = &GetRotateProperty();
break;
case eCSSProperty_transform:
transform = &GetTransformProperty();
break;
default:
MOZ_ASSERT_UNREACHABLE(
"Should only need to check in transform properties");
return Size(1.0, 1.0);
}
TransformReferenceBox refBox(aFrame);
Matrix4x4 t =
ReadTransforms(translate ? *translate : StyleTranslate::None(),
rotate ? *rotate : StyleRotate::None(),
scale ? *scale : StyleScale::None(), Nothing(),
transform ? *transform : StyleTransform(), refBox,
aFrame->PresContext()->AppUnitsPerDevPixel());
Matrix transform2d;
bool canDraw2D = t.CanDraw2D(&transform2d);
if (!canDraw2D) {
return Size();
}
return transform2d.ScaleFactors(true);
RefPtr<const nsCSSValueSharedList> list = GetTransformList();
return nsStyleTransformMatrix::GetScaleValue(list, aFrame);
}
void AnimationValue::SerializeSpecifiedValue(nsCSSPropertyID aProperty,
@ -301,63 +341,101 @@ AnimationValue AnimationValue::FromString(nsCSSPropertyID aProperty,
return result;
}
StyleRotate RotateFromLayers(const layers::Rotate& aRotate) {
switch (aRotate.type()) {
case layers::Rotate::Tnull_t:
return StyleRotate::None();
case layers::Rotate::TRotation: {
const layers::CSSAngle& angle = aRotate.get_Rotation().angle();
return StyleRotate::Rotate(GetCSSAngle(angle));
}
case layers::Rotate::TRotation3D: {
float x = aRotate.get_Rotation3D().x();
float y = aRotate.get_Rotation3D().y();
float z = aRotate.get_Rotation3D().z();
const layers::CSSAngle& angle = aRotate.get_Rotation3D().angle();
return StyleRotate::Rotate3D(x, y, z, GetCSSAngle(angle));
}
default:
MOZ_ASSERT_UNREACHABLE("Unknown rotate value?");
return StyleRotate::None();
}
}
/* static */
already_AddRefed<RawServoAnimationValue> AnimationValue::FromAnimatable(
nsCSSPropertyID aProperty, const layers::Animatable& aAnimatable) {
RefPtr<RawServoAnimationValue> result;
switch (aAnimatable.type()) {
case layers::Animatable::Tnull_t:
break;
case layers::Animatable::TArrayOfTransformFunction: {
nsTArray<StyleTransformOperation> ops =
CreateTransformList(aAnimatable.get_ArrayOfTransformFunction());
;
return Servo_AnimationValue_Transform(ops.Elements(), ops.Length())
.Consume();
const InfallibleTArray<layers::TransformFunction>& transforms =
aAnimatable.get_ArrayOfTransformFunction();
auto listOrError = CreateCSSValueList(transforms);
if (listOrError.isOk()) {
RefPtr<nsCSSValueSharedList> list = listOrError.unwrap();
MOZ_ASSERT(list, "Transform list should be non null");
result = Servo_AnimationValue_Transform(eCSSProperty_transform, list)
.Consume();
}
break;
}
case layers::Animatable::Tfloat:
return Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume();
result = Servo_AnimationValue_Opacity(aAnimatable.get_float()).Consume();
break;
case layers::Animatable::Tnscolor:
return Servo_AnimationValue_Color(aProperty, aAnimatable.get_nscolor())
.Consume();
result = Servo_AnimationValue_Color(aProperty, aAnimatable.get_nscolor())
.Consume();
break;
case layers::Animatable::TRotate: {
auto rotate = RotateFromLayers(aAnimatable.get_Rotate());
return Servo_AnimationValue_Rotate(&rotate).Consume();
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
list->mHead = new nsCSSValueList;
const layers::Rotate& r = aAnimatable.get_Rotate();
if (r.type() == layers::Rotate::Tnull_t) {
list->mHead->mValue.SetNoneValue();
} else {
RefPtr<nsCSSValue::Array> arr;
if (r.type() == layers::Rotate::TRotation) {
const layers::CSSAngle& angle = r.get_Rotation().angle();
arr = AppendFunction(eCSSKeyword_rotate);
auto rv = SetCSSAngle(angle, arr->Item(1));
if (rv.isErr()) {
arr->Item(1).SetFloatValue(0.0, eCSSUnit_Degree);
}
} else {
MOZ_ASSERT(r.type() == layers::Rotate::TRotation3D,
"Should be rotate3D");
float x = r.get_Rotation3D().x();
float y = r.get_Rotation3D().y();
float z = r.get_Rotation3D().z();
const layers::CSSAngle& angle = r.get_Rotation3D().angle();
arr = AppendFunction(eCSSKeyword_rotate3d);
arr->Item(1).SetFloatValue(x, eCSSUnit_Number);
arr->Item(2).SetFloatValue(y, eCSSUnit_Number);
arr->Item(3).SetFloatValue(z, eCSSUnit_Number);
auto rv = SetCSSAngle(angle, arr->Item(4));
if (rv.isErr()) {
arr->Item(4).SetFloatValue(0.0, eCSSUnit_Degree);
}
}
list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function);
}
result =
Servo_AnimationValue_Transform(eCSSProperty_rotate, list).Consume();
break;
}
case layers::Animatable::TScale: {
const layers::Scale& s = aAnimatable.get_Scale();
auto scale = StyleScale::Scale3D(s.x(), s.y(), s.z());
return Servo_AnimationValue_Scale(&scale).Consume();
const layers::Scale& scale = aAnimatable.get_Scale();
RefPtr<nsCSSValue::Array> arr = AppendFunction(eCSSKeyword_scale3d);
arr->Item(1).SetFloatValue(scale.x(), eCSSUnit_Number);
arr->Item(2).SetFloatValue(scale.y(), eCSSUnit_Number);
arr->Item(3).SetFloatValue(scale.z(), eCSSUnit_Number);
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
list->mHead = new nsCSSValueList;
list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function);
result =
Servo_AnimationValue_Transform(eCSSProperty_scale, list).Consume();
break;
}
case layers::Animatable::TTranslation: {
const layers::Translation& t = aAnimatable.get_Translation();
auto translate = StyleTranslate::Translate3D(
LengthPercentage::FromPixels(t.x()),
LengthPercentage::FromPixels(t.y()), Length{t.z()});
return Servo_AnimationValue_Translate(&translate).Consume();
const layers::Translation& translate = aAnimatable.get_Translation();
RefPtr<nsCSSValue::Array> arr = AppendFunction(eCSSKeyword_translate3d);
arr->Item(1).SetFloatValue(translate.x(), eCSSUnit_Pixel);
arr->Item(2).SetFloatValue(translate.y(), eCSSUnit_Pixel);
arr->Item(3).SetFloatValue(translate.z(), eCSSUnit_Pixel);
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
list->mHead = new nsCSSValueList;
list->mHead->mValue.SetArrayValue(arr, eCSSUnit_Function);
result = Servo_AnimationValue_Transform(eCSSProperty_translate, list)
.Consume();
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unsupported type");
}
return nullptr;
return result.forget();
}

View File

@ -77,11 +77,8 @@ struct AnimationValue {
// Currently only background-color is supported.
nscolor GetColor(nscolor aForegroundColor) const;
// Return a transform list for the transform property.
const mozilla::StyleTransform& GetTransformProperty() const;
const mozilla::StyleScale& GetScaleProperty() const;
const mozilla::StyleTranslate& GetTranslateProperty() const;
const mozilla::StyleRotate& GetRotateProperty() const;
// Return the transform list as a RefPtr.
already_AddRefed<const nsCSSValueSharedList> GetTransformList() const;
// Return the scale for mServo, which is calculated with reference to aFrame.
mozilla::gfx::Size GetScaleValue(const nsIFrame* aFrame) const;

View File

@ -1099,7 +1099,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetPerspectiveOrigin() {
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetTransform() {
const nsStyleDisplay* display = StyleDisplay();
return GetTransformValue(display->mTransform);
return GetTransformValue(display->mSpecifiedTransform);
}
/* static */
@ -2502,12 +2502,14 @@ bool nsComputedDOMStyle::GetFrameBorderRectHeight(nscoord& aHeight) {
* "matrix" wrapper.
*/
already_AddRefed<CSSValue> nsComputedDOMStyle::GetTransformValue(
const StyleTransform& aTransform) {
nsCSSValueSharedList* aSpecifiedTransform) {
/* If there are no transforms, then we should construct a single-element
* entry and hand it back.
*/
if (aTransform.IsNone()) {
if (!aSpecifiedTransform) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
/* Set it to "none." */
val->SetIdent(eCSSKeyword_none);
return val.forget();
}
@ -2531,7 +2533,8 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetTransformValue(
nsSize(0, 0));
gfx::Matrix4x4 matrix = nsStyleTransformMatrix::ReadTransforms(
aTransform, refBox, float(mozilla::AppUnitsPerCSSPixel()));
aSpecifiedTransform->mHead, refBox,
float(mozilla::AppUnitsPerCSSPixel()));
return MatrixToCSSValue(matrix);
}

View File

@ -188,7 +188,8 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
already_AddRefed<CSSValue> GetMarginWidthFor(mozilla::Side aSide);
already_AddRefed<CSSValue> GetTransformValue(const mozilla::StyleTransform&);
already_AddRefed<CSSValue> GetTransformValue(
nsCSSValueSharedList* aSpecifiedTransform);
// Appends all aLineNames (may be empty) space-separated to aResult.
void AppendGridLineNames(nsString& aResult,

View File

@ -682,6 +682,12 @@ enum class StyleWhiteSpace : uint8_t {
// See nsStyleSVG
// -moz-context-properties
#define NS_STYLE_CONTEXT_PROPERTY_FILL (1 << 0)
#define NS_STYLE_CONTEXT_PROPERTY_STROKE (1 << 1)
#define NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY (1 << 2)
#define NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY (1 << 3)
/*
* -moz-window-shadow
* Also used in widget code

View File

@ -85,6 +85,8 @@ static bool DefinitelyEqualImages(const nsStyleImageRequest* aRequest1,
return aRequest1->DefinitelyEquals(*aRequest2);
}
static bool AreShadowArraysEqual(nsCSSShadowArray* lhs, nsCSSShadowArray* rhs);
// --------------------
// nsStyleFont
//
@ -478,12 +480,12 @@ nsChangeHint nsStyleOutline::CalcDifference(
//
nsStyleList::nsStyleList(const Document& aDocument)
: mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
mQuotes{StyleArcSlice<StyleQuotePair>(Servo_Quotes_GetInitialValue())},
mMozListReversed(StyleMozListReversed::False) {
MOZ_COUNT_CTOR(nsStyleList);
MOZ_ASSERT(NS_IsMainThread());
mCounterStyle = nsGkAtoms::disc;
mQuotes = Servo_Quotes_GetInitialValue().Consume();
}
nsStyleList::~nsStyleList() { MOZ_COUNT_DTOR(nsStyleList); }
@ -512,7 +514,8 @@ nsChangeHint nsStyleList::CalcDifference(
const nsStyleList& aNewData, const nsStyleDisplay& aOldDisplay) const {
// If the quotes implementation is ever going to change we might not need
// a framechange here and a reflow should be sufficient. See bug 35768.
if (mQuotes != aNewData.mQuotes) {
if (mQuotes != aNewData.mQuotes &&
!Servo_Quotes_Equal(mQuotes.get(), aNewData.mQuotes.get())) {
return nsChangeHint_ReconstructFrame;
}
nsChangeHint hint = nsChangeHint(0);
@ -671,7 +674,6 @@ nsChangeHint nsStyleColumn::CalcDifference(
nsStyleSVG::nsStyleSVG(const Document& aDocument)
: mFill(eStyleSVGPaintType_Color), // Will be initialized to NS_RGB(0,0,0)
mStroke(eStyleSVGPaintType_None),
mMozContextProperties{{}, {0}},
mStrokeDashoffset(LengthPercentage::Zero()),
mStrokeWidth(LengthPercentage::FromPixels(1.0f)),
mFillOpacity(1.0f),
@ -686,6 +688,7 @@ nsStyleSVG::nsStyleSVG(const Document& aDocument)
mStrokeLinecap(NS_STYLE_STROKE_LINECAP_BUTT),
mStrokeLinejoin(NS_STYLE_STROKE_LINEJOIN_MITER),
mTextAnchor(NS_STYLE_TEXT_ANCHOR_START),
mContextPropsBits(0),
mContextFlags(
(eStyleSVGOpacitySource_Normal << FILL_OPACITY_SOURCE_SHIFT) |
(eStyleSVGOpacitySource_Normal << STROKE_OPACITY_SOURCE_SHIFT)) {
@ -701,7 +704,7 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
mMarkerMid(aSource.mMarkerMid),
mMarkerStart(aSource.mMarkerStart),
mStrokeDasharray(aSource.mStrokeDasharray),
mMozContextProperties(aSource.mMozContextProperties),
mContextProps(aSource.mContextProps),
mStrokeDashoffset(aSource.mStrokeDashoffset),
mStrokeWidth(aSource.mStrokeWidth),
mFillOpacity(aSource.mFillOpacity),
@ -716,6 +719,7 @@ nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
mStrokeLinecap(aSource.mStrokeLinecap),
mStrokeLinejoin(aSource.mStrokeLinejoin),
mTextAnchor(aSource.mTextAnchor),
mContextPropsBits(aSource.mContextPropsBits),
mContextFlags(aSource.mContextFlags) {
MOZ_COUNT_CTOR(nsStyleSVG);
}
@ -793,12 +797,12 @@ nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const {
mShapeRendering != aNewData.mShapeRendering ||
mStrokeDasharray != aNewData.mStrokeDasharray ||
mContextFlags != aNewData.mContextFlags ||
mMozContextProperties.bits != aNewData.mMozContextProperties.bits) {
mContextPropsBits != aNewData.mContextPropsBits) {
return hint | nsChangeHint_RepaintFrame;
}
if (!hint) {
if (mMozContextProperties.idents != aNewData.mMozContextProperties.idents) {
if (mContextProps != aNewData.mContextProps) {
hint = nsChangeHint_NeutralChange;
}
}
@ -970,12 +974,13 @@ void StyleShapeSource::DoDestroy() {
// --------------------
// nsStyleFilter
//
nsStyleFilter::nsStyleFilter() : mType(NS_STYLE_FILTER_NONE), mURL(nullptr) {
nsStyleFilter::nsStyleFilter()
: mType(NS_STYLE_FILTER_NONE), mDropShadow(nullptr) {
MOZ_COUNT_CTOR(nsStyleFilter);
}
nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
: mType(NS_STYLE_FILTER_NONE), mURL(nullptr) {
: mType(NS_STYLE_FILTER_NONE), mDropShadow(nullptr) {
MOZ_COUNT_CTOR(nsStyleFilter);
if (aSource.mType == NS_STYLE_FILTER_URL) {
SetURL(aSource.mURL);
@ -1018,7 +1023,7 @@ bool nsStyleFilter::operator==(const nsStyleFilter& aOther) const {
if (mType == NS_STYLE_FILTER_URL) {
return DefinitelyEqualURIs(mURL, aOther.mURL);
} else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
return mDropShadow == aOther.mDropShadow;
return *mDropShadow == *aOther.mDropShadow;
} else if (mType != NS_STYLE_FILTER_NONE) {
return mFilterParameter == aOther.mFilterParameter;
}
@ -1028,7 +1033,8 @@ bool nsStyleFilter::operator==(const nsStyleFilter& aOther) const {
void nsStyleFilter::ReleaseRef() {
if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
mDropShadow.~StyleSimpleShadow();
NS_ASSERTION(mDropShadow, "expected pointer");
mDropShadow->Release();
} else if (mType == NS_STYLE_FILTER_URL) {
NS_ASSERTION(mURL, "expected pointer");
mURL->Release();
@ -1051,9 +1057,11 @@ bool nsStyleFilter::SetURL(css::URLValue* aURL) {
return true;
}
void nsStyleFilter::SetDropShadow(const StyleSimpleShadow& aSrc) {
void nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow) {
NS_ASSERTION(aDropShadow, "expected pointer");
ReleaseRef();
new (&mDropShadow) StyleSimpleShadow(aSrc);
mDropShadow = aDropShadow;
mDropShadow->AddRef();
mType = NS_STYLE_FILTER_DROP_SHADOW;
}
@ -2916,7 +2924,7 @@ nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
mOrient(StyleOrient::Inline),
mIsolation(NS_STYLE_ISOLATION_AUTO),
mTopLayer(NS_STYLE_TOP_LAYER_NONE),
mWillChange{{}, {0}},
mWillChangeBitField({0}),
mTouchAction(StyleTouchAction_AUTO),
mScrollBehavior(NS_STYLE_SCROLL_BEHAVIOR_AUTO),
mOverscrollBehaviorX(StyleOverscrollBehavior::Auto),
@ -2983,6 +2991,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
mOrient(aSource.mOrient),
mIsolation(aSource.mIsolation),
mTopLayer(aSource.mTopLayer),
mWillChangeBitField(aSource.mWillChangeBitField),
mWillChange(aSource.mWillChange),
mTouchAction(aSource.mTouchAction),
mScrollBehavior(aSource.mScrollBehavior),
@ -2997,10 +3006,10 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
mBackfaceVisibility(aSource.mBackfaceVisibility),
mTransformStyle(aSource.mTransformStyle),
mTransformBox(aSource.mTransformBox),
mTransform(aSource.mTransform),
mRotate(aSource.mRotate),
mTranslate(aSource.mTranslate),
mScale(aSource.mScale),
mSpecifiedTransform(aSource.mSpecifiedTransform),
mSpecifiedRotate(aSource.mSpecifiedRotate),
mSpecifiedTranslate(aSource.mSpecifiedTranslate),
mSpecifiedScale(aSource.mSpecifiedScale),
// We intentionally leave mIndividualTransform as null, is the caller's
// responsibility to call GenerateCombinedIndividualTransform when
// appropriate.
@ -3030,7 +3039,40 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
MOZ_COUNT_CTOR(nsStyleDisplay);
}
static void ReleaseSharedListOnMainThread(const char* aName,
RefPtr<nsCSSValueSharedList>& aList) {
// We don't allow releasing nsCSSValues with refcounted data in the Servo
// traversal, since the refcounts aren't threadsafe. Since Servo may trigger
// the deallocation of style structs during styling, we need to handle it
// here.
if (aList && ServoStyleSet::IsInServoTraversal()) {
// The default behavior of NS_ReleaseOnMainThreadSystemGroup is to only
// proxy the release if we're not already on the main thread. This is a nice
// optimization for the cases we happen to be doing a sequential traversal
// (i.e. a single-core machine), but it trips our assertions which check
// whether we're in a Servo traversal, parallel or not. So we
// unconditionally proxy in debug builds.
bool alwaysProxy =
#ifdef DEBUG
true;
#else
false;
#endif
NS_ReleaseOnMainThreadSystemGroup(aName, aList.forget(), alwaysProxy);
}
}
nsStyleDisplay::~nsStyleDisplay() {
ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedTransform",
mSpecifiedTransform);
ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedRotate",
mSpecifiedRotate);
ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedTranslate",
mSpecifiedTranslate);
ReleaseSharedListOnMainThread("nsStyleDisplay::mSpecifiedScale",
mSpecifiedScale);
ReleaseSharedListOnMainThread("nsStyleDisplay::mIndividualTransform",
mIndividualTransform);
MOZ_COUNT_DTOR(nsStyleDisplay);
}
@ -3042,16 +3084,22 @@ void nsStyleDisplay::TriggerImageLoads(Document& aDocument,
aDocument, aOldStyle ? &aOldStyle->mShapeOutside : nullptr);
}
template <typename TransformLike>
static inline bool TransformListChanged(
const RefPtr<nsCSSValueSharedList>& aList,
const RefPtr<nsCSSValueSharedList>& aNewList) {
return !aList != !aNewList || (aList && *aList != *aNewList);
}
static inline nsChangeHint CompareTransformValues(
const TransformLike& aOldTransform, const TransformLike& aNewTransform) {
const RefPtr<nsCSSValueSharedList>& aList,
const RefPtr<nsCSSValueSharedList>& aNewList) {
nsChangeHint result = nsChangeHint(0);
// Note: If we add a new change hint for transform changes here, we have to
// modify KeyframeEffect::CalculateCumulativeChangeHint too!
if (aOldTransform != aNewTransform) {
if (!aList != !aNewList || (aList && *aList != *aNewList)) {
result |= nsChangeHint_UpdateTransformLayer;
if (!aOldTransform.IsNone() && !aNewTransform.IsNone()) {
if (aList && aNewList) {
result |= nsChangeHint_UpdatePostTransformOverflow;
} else {
result |= nsChangeHint_UpdateOverflow;
@ -3200,10 +3248,14 @@ nsChangeHint nsStyleDisplay::CalcDifference(
*/
nsChangeHint transformHint = nsChangeHint(0);
transformHint |= CompareTransformValues(mTransform, aNewData.mTransform);
transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
transformHint |= CompareTransformValues(mScale, aNewData.mScale);
transformHint |= CompareTransformValues(mSpecifiedTransform,
aNewData.mSpecifiedTransform);
transformHint |=
CompareTransformValues(mSpecifiedRotate, aNewData.mSpecifiedRotate);
transformHint |= CompareTransformValues(mSpecifiedTranslate,
aNewData.mSpecifiedTranslate);
transformHint |=
CompareTransformValues(mSpecifiedScale, aNewData.mSpecifiedScale);
transformHint |= CompareMotionValues(mMotion.get(), aNewData.mMotion.get());
if (mTransformOrigin != aNewData.mTransformOrigin) {
@ -3246,7 +3298,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(
// TODO(emilio): Should add xor to the generated cbindgen type.
auto willChangeBitsChanged =
StyleWillChangeBits{static_cast<decltype(StyleWillChangeBits::bits)>(
mWillChange.bits.bits ^ aNewData.mWillChange.bits.bits)};
mWillChangeBitField.bits ^ aNewData.mWillChangeBitField.bits)};
if (willChangeBitsChanged &
(StyleWillChangeBits_STACKING_CONTEXT | StyleWillChangeBits_SCROLL |
@ -3316,6 +3368,68 @@ nsChangeHint nsStyleDisplay::CalcDifference(
return hint;
}
bool nsStyleDisplay::TransformChanged(const nsStyleDisplay& aNewData) const {
return TransformListChanged(mSpecifiedTransform,
aNewData.mSpecifiedTransform);
}
/* static */
already_AddRefed<nsCSSValueSharedList>
nsStyleDisplay::GenerateCombinedIndividualTransform(
nsCSSValueSharedList* aTranslate, nsCSSValueSharedList* aRotate,
nsCSSValueSharedList* aScale) {
// Follow the order defined in the spec to append transform functions.
// https://drafts.csswg.org/css-transforms-2/#ctm
AutoTArray<nsCSSValueSharedList*, 3> shareLists;
if (aTranslate) {
shareLists.AppendElement(aTranslate);
}
if (aRotate) {
shareLists.AppendElement(aRotate);
}
if (aScale) {
shareLists.AppendElement(aScale);
}
if (shareLists.IsEmpty()) {
return nullptr;
}
if (shareLists.Length() == 1) {
return RefPtr<nsCSSValueSharedList>(shareLists[0]).forget();
}
// In common, we may have 3 transform functions:
// 1. one rotate function in aRotate,
// 2. one translate function in aTranslate,
// 3. one scale function in aScale.
AutoTArray<nsCSSValueList*, 3> valueLists;
for (auto list : shareLists) {
if (list) {
valueLists.AppendElement(list->mHead->Clone());
}
}
// Check we have at least one list or else valueLists.Length() - 1 below will
// underflow.
MOZ_ASSERT(!valueLists.IsEmpty());
for (uint32_t i = 0; i < valueLists.Length() - 1; i++) {
valueLists[i]->mNext = valueLists[i + 1];
}
RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList(valueLists[0]);
return list.forget();
}
void nsStyleDisplay::GenerateCombinedIndividualTransform() {
MOZ_ASSERT(!mIndividualTransform);
mIndividualTransform = GenerateCombinedIndividualTransform(
mSpecifiedTranslate, mSpecifiedRotate, mSpecifiedScale);
}
// --------------------
// nsStyleVisibility
//
@ -3581,6 +3695,24 @@ nsChangeHint nsStyleTextReset::CalcDifference(
return nsChangeHint(0);
}
// Returns true if the given shadow-arrays are equal.
static bool AreShadowArraysEqual(nsCSSShadowArray* lhs, nsCSSShadowArray* rhs) {
if (lhs == rhs) {
return true;
}
if (!lhs || !rhs || lhs->Length() != rhs->Length()) {
return false;
}
for (uint32_t i = 0; i < lhs->Length(); ++i) {
if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i)) {
return false;
}
}
return true;
}
// --------------------
// nsStyleText
//
@ -3609,7 +3741,8 @@ nsStyleText::nsStyleText(const Document& aDocument)
mLetterSpacing({0.}),
mLineHeight(StyleLineHeight::Normal()),
mTextIndent(LengthPercentage::Zero()),
mWebkitTextStrokeWidth(0) {
mWebkitTextStrokeWidth(0),
mTextShadow(nullptr) {
MOZ_COUNT_CTOR(nsStyleText);
RefPtr<nsAtom> language = aDocument.GetContentLanguageAsAtomForStyle();
mTextEmphasisPosition =
@ -3698,7 +3831,7 @@ nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
nsChangeHint_RepaintFrame;
}
if (mTextShadow != aNewData.mTextShadow ||
if (!AreShadowArraysEqual(mTextShadow, aNewData.mTextShadow) ||
mTextEmphasisStyle != aNewData.mTextEmphasisStyle ||
mTextEmphasisStyleString != aNewData.mTextEmphasisStyleString ||
mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth) {
@ -3880,6 +4013,7 @@ nsStyleUIReset::nsStyleUIReset(const Document& aDocument)
mWindowDragging(StyleWindowDragging::Default),
mWindowShadow(NS_STYLE_WINDOW_SHADOW_DEFAULT),
mWindowOpacity(1.0),
mSpecifiedWindowTransform(nullptr),
mWindowTransformOrigin{LengthPercentage::FromPercentage(0.5),
LengthPercentage::FromPercentage(0.5),
{0.}} {
@ -3894,13 +4028,16 @@ nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
mWindowDragging(aSource.mWindowDragging),
mWindowShadow(aSource.mWindowShadow),
mWindowOpacity(aSource.mWindowOpacity),
mMozWindowTransform(aSource.mMozWindowTransform),
mSpecifiedWindowTransform(aSource.mSpecifiedWindowTransform),
mWindowTransformOrigin(aSource.mWindowTransformOrigin) {
MOZ_COUNT_CTOR(nsStyleUIReset);
}
nsStyleUIReset::~nsStyleUIReset() {
MOZ_COUNT_DTOR(nsStyleUIReset);
ReleaseSharedListOnMainThread("nsStyleUIReset::mSpecifiedWindowTransform",
mSpecifiedWindowTransform);
}
nsChangeHint nsStyleUIReset::CalcDifference(
@ -3931,7 +4068,10 @@ nsChangeHint nsStyleUIReset::CalcDifference(
}
if (mWindowOpacity != aNewData.mWindowOpacity ||
mMozWindowTransform != aNewData.mMozWindowTransform) {
!mSpecifiedWindowTransform != !aNewData.mSpecifiedWindowTransform ||
(mSpecifiedWindowTransform &&
*mSpecifiedWindowTransform != *aNewData.mSpecifiedWindowTransform) ||
mWindowTransformOrigin != aNewData.mWindowTransformOrigin) {
hint |= nsChangeHint_UpdateWidgetProperties;
}
@ -3947,7 +4087,8 @@ nsChangeHint nsStyleUIReset::CalcDifference(
//
nsStyleEffects::nsStyleEffects(const Document&)
: mClip(0, 0, 0, 0),
: mBoxShadow(nullptr),
mClip(0, 0, 0, 0),
mOpacity(1.0f),
mClipFlags(NS_STYLE_CLIP_AUTO),
mMixBlendMode(NS_STYLE_BLEND_NORMAL) {
@ -3970,7 +4111,7 @@ nsChangeHint nsStyleEffects::CalcDifference(
const nsStyleEffects& aNewData) const {
nsChangeHint hint = nsChangeHint(0);
if (mBoxShadow != aNewData.mBoxShadow) {
if (!AreShadowArraysEqual(mBoxShadow, aNewData.mBoxShadow)) {
// Update overflow regions & trigger DLBI to be sure it's noticed.
// Also request a repaint, since it's possible that only the color
// of the shadow is changing (and UpdateOverflow/SchedulePaint won't

View File

@ -747,6 +747,109 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding {
}
};
struct nsCSSShadowItem {
nscoord mXOffset;
nscoord mYOffset;
nscoord mRadius;
nscoord mSpread;
mozilla::StyleColor mColor;
bool mInset;
nsCSSShadowItem()
: mXOffset(0),
mYOffset(0),
mRadius(0),
mSpread(0),
mColor(mozilla::StyleColor::CurrentColor()),
mInset(false) {
MOZ_COUNT_CTOR(nsCSSShadowItem);
}
~nsCSSShadowItem() { MOZ_COUNT_DTOR(nsCSSShadowItem); }
bool operator==(const nsCSSShadowItem& aOther) const {
return (mXOffset == aOther.mXOffset && mYOffset == aOther.mYOffset &&
mRadius == aOther.mRadius && mSpread == aOther.mSpread &&
mInset == aOther.mInset && mColor == aOther.mColor);
}
bool operator!=(const nsCSSShadowItem& aOther) const {
return !(*this == aOther);
}
};
class nsCSSShadowArray final {
public:
void* operator new(size_t aBaseSize, uint32_t aArrayLen) {
// We can allocate both this nsCSSShadowArray and the
// actual array in one allocation. The amount of memory to
// allocate is equal to the class's size + the number of bytes for all
// but the first array item (because aBaseSize includes one
// item, see the private declarations)
return ::operator new(aBaseSize +
(aArrayLen - 1) * sizeof(nsCSSShadowItem));
}
void operator delete(void* aPtr) { ::operator delete(aPtr); }
explicit nsCSSShadowArray(uint32_t aArrayLen) : mLength(aArrayLen) {
for (uint32_t i = 1; i < mLength; ++i) {
// Make sure we call the constructors of each nsCSSShadowItem
// (the first one is called for us because we declared it under private)
new (&mArray[i]) nsCSSShadowItem();
}
}
private:
// Private destructor, to discourage deletion outside of Release():
~nsCSSShadowArray() {
for (uint32_t i = 1; i < mLength; ++i) {
mArray[i].~nsCSSShadowItem();
}
}
public:
uint32_t Length() const { return mLength; }
nsCSSShadowItem* ShadowAt(uint32_t i) {
MOZ_ASSERT(i < mLength,
"Accessing too high an index in the text shadow array!");
return &mArray[i];
}
const nsCSSShadowItem* ShadowAt(uint32_t i) const {
MOZ_ASSERT(i < mLength,
"Accessing too high an index in the text shadow array!");
return &mArray[i];
}
bool HasShadowWithInset(bool aInset) {
for (uint32_t i = 0; i < mLength; ++i) {
if (mArray[i].mInset == aInset) {
return true;
}
}
return false;
}
bool operator==(const nsCSSShadowArray& aOther) const {
if (mLength != aOther.Length()) {
return false;
}
for (uint32_t i = 0; i < mLength; ++i) {
if (ShadowAt(i) != aOther.ShadowAt(i)) {
return false;
}
}
return true;
}
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCSSShadowArray)
private:
uint32_t mLength;
nsCSSShadowItem mArray[1]; // This MUST be the last item
};
// Border widths are rounded to the nearest-below integer number of pixels,
// but values between zero and one device pixels are always rounded up to
// one device pixel.
@ -1000,7 +1103,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList {
nsStyleList& operator=(const nsStyleList& aOther) = delete;
public:
mozilla::StyleQuotes mQuotes;
RefPtr<RawServoQuotes> mQuotes;
nsRect mImageRegion; // the rect to use within an image
mozilla::StyleMozListReversed
mMozListReversed; // true in an <ol reversed> scope
@ -1383,7 +1486,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
mozilla::LengthPercentage mTextIndent;
nscoord mWebkitTextStrokeWidth; // coord
mozilla::StyleArcSlice<mozilla::StyleSimpleShadow> mTextShadow;
RefPtr<nsCSSShadowArray> mTextShadow; // nullptr in case of a zero-length
nsString mTextEmphasisStyleString;
@ -1444,7 +1547,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
bool HasWebkitTextStroke() const { return mWebkitTextStrokeWidth > 0; }
bool HasTextShadow() const { return !mTextShadow.IsEmpty(); }
// These are defined in nsStyleStructInlines.h.
inline bool HasTextShadow() const;
inline nsCSSShadowArray* GetTextShadow() const;
// The aContextFrame argument on each of these is the frame this
// style struct is for. If the frame is for SVG text or inside ruby,
@ -1561,9 +1666,12 @@ struct StyleAnimation {
struct StyleSVGPath final {
StyleSVGPath(StyleForgottenArcSlicePtr<StylePathCommand> aPath,
StyleFillRule aFill)
: mPath(aPath), mFillRule(aFill) {}
: mPath(aPath),
mFillRule(aFill) {}
Span<const StylePathCommand> Path() const { return mPath.AsSpan(); }
Span<const StylePathCommand> Path() const {
return mPath.AsSpan();
}
StyleFillRule FillRule() const { return mFillRule; }
@ -1699,6 +1807,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
nsChangeHint CalcDifference(const nsStyleDisplay& aNewData) const;
bool TransformChanged(const nsStyleDisplay& aNewData) const;
// We guarantee that if mBinding is non-null, so are mBinding->GetURI() and
// mBinding->mOriginPrincipal.
RefPtr<mozilla::css::URLValue> mBinding;
@ -1728,7 +1838,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
mozilla::StyleOrient mOrient;
uint8_t mIsolation; // NS_STYLE_ISOLATION_*
uint8_t mTopLayer; // NS_STYLE_TOP_LAYER_*
mozilla::StyleWillChange mWillChange;
// Stores a bitfield representation of the properties that are frequently
// queried. This should match mWillChange. Also tracks if any of the
// properties in the will-change list require a stacking context.
mozilla::StyleWillChangeBits mWillChangeBitField;
nsTArray<RefPtr<nsAtom>> mWillChange;
mozilla::StyleTouchAction mTouchAction;
uint8_t mScrollBehavior; // NS_STYLE_SCROLL_BEHAVIOR_*
@ -1750,12 +1864,13 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
uint8_t mBackfaceVisibility;
uint8_t mTransformStyle;
StyleGeometryBox mTransformBox;
mozilla::StyleTransform mTransform;
mozilla::StyleRotate mRotate;
mozilla::StyleTranslate mTranslate;
mozilla::StyleScale mScale;
RefPtr<nsCSSValueSharedList> mSpecifiedTransform;
RefPtr<nsCSSValueSharedList> mSpecifiedRotate;
RefPtr<nsCSSValueSharedList> mSpecifiedTranslate;
RefPtr<nsCSSValueSharedList> mSpecifiedScale;
// Used to store the final combination of mSpecifiedRotate,
// mSpecifiedTranslate, and mSpecifiedScale.
RefPtr<nsCSSValueSharedList> mIndividualTransform;
mozilla::UniquePtr<mozilla::StyleMotion> mMotion;
mozilla::StyleTransformOrigin mTransformOrigin;
@ -1996,19 +2111,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
(mozilla::StyleDisplay::Table != mDisplay) && !IsInnerTableStyle();
}
/* Returns whether the element has the transform property or a related
* property. */
/* Returns whether the element has the -moz-transform property
* or a related property. */
bool HasTransformStyle() const {
return HasTransformProperty() || HasIndividualTransform() ||
return mSpecifiedTransform || mSpecifiedRotate || mSpecifiedTranslate ||
mSpecifiedScale ||
mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
(mWillChange.bits & mozilla::StyleWillChangeBits_TRANSFORM) ||
(mWillChangeBitField & mozilla::StyleWillChangeBits_TRANSFORM) ||
(mMotion && mMotion->HasPath());
}
bool HasTransformProperty() const { return !mTransform._0.IsEmpty(); }
bool HasIndividualTransform() const {
return !mRotate.IsNone() || !mTranslate.IsNone() || !mScale.IsNone();
return mSpecifiedRotate || mSpecifiedTranslate || mSpecifiedScale;
}
bool HasPerspectiveStyle() const { return !mChildPerspective.IsNone(); }
@ -2115,6 +2229,23 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() const;
inline bool IsFixedPosContainingBlockForTransformSupportingFrames() const;
/**
* Returns the final combined individual transform.
**/
already_AddRefed<nsCSSValueSharedList> GetCombinedTransform() const {
return mIndividualTransform ? do_AddRef(mIndividualTransform) : nullptr;
}
/**
* Returns the combined transform list based on translate, rotate, scale
* individual transforms. The combination order is defined in
* https://drafts.csswg.org/css-transforms-2/#ctm
*/
static already_AddRefed<nsCSSValueSharedList>
GenerateCombinedIndividualTransform(nsCSSValueSharedList* aTranslate,
nsCSSValueSharedList* aRotate,
nsCSSValueSharedList* aScale);
void GenerateCombinedIndividualTransform();
};
@ -2358,7 +2489,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset {
mozilla::StyleWindowDragging mWindowDragging;
uint8_t mWindowShadow;
float mWindowOpacity;
mozilla::StyleTransform mMozWindowTransform;
RefPtr<nsCSSValueSharedList> mSpecifiedWindowTransform;
mozilla::StyleTransformOrigin mWindowTransformOrigin;
};
@ -2567,7 +2698,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
RefPtr<mozilla::css::URLValue> mMarkerMid;
RefPtr<mozilla::css::URLValue> mMarkerStart;
nsTArray<mozilla::NonNegativeLengthPercentage> mStrokeDasharray;
mozilla::StyleMozContextProperties mMozContextProperties;
nsTArray<RefPtr<nsAtom>> mContextProps;
mozilla::LengthPercentage mStrokeDashoffset;
mozilla::NonNegativeLengthPercentage mStrokeWidth;
@ -2580,17 +2711,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
uint8_t mColorInterpolation; // NS_STYLE_COLOR_INTERPOLATION_*
uint8_t mColorInterpolationFilters; // NS_STYLE_COLOR_INTERPOLATION_*
mozilla::StyleFillRule mFillRule;
uint8_t mPaintOrder; // bitfield of NS_STYLE_PAINT_ORDER_* values
uint8_t mShapeRendering; // NS_STYLE_SHAPE_RENDERING_*
uint8_t mStrokeLinecap; // NS_STYLE_STROKE_LINECAP_*
uint8_t mStrokeLinejoin; // NS_STYLE_STROKE_LINEJOIN_*
uint8_t mTextAnchor; // NS_STYLE_TEXT_ANCHOR_*
uint8_t mPaintOrder; // bitfield of NS_STYLE_PAINT_ORDER_* values
uint8_t mShapeRendering; // NS_STYLE_SHAPE_RENDERING_*
uint8_t mStrokeLinecap; // NS_STYLE_STROKE_LINECAP_*
uint8_t mStrokeLinejoin; // NS_STYLE_STROKE_LINEJOIN_*
uint8_t mTextAnchor; // NS_STYLE_TEXT_ANCHOR_*
uint8_t mContextPropsBits; // bitfield of
// NS_STYLE_CONTEXT_PROPERTY_FILL_* values
/// Returns true if style has been set to expose the computed values of
/// certain properties (such as 'fill') to the contents of any linked images.
bool ExposesContextProperties() const {
return bool(mMozContextProperties.bits);
}
bool ExposesContextProperties() const { return bool(mContextPropsBits); }
nsStyleSVGOpacitySource FillOpacitySource() const {
uint8_t value =
@ -2683,11 +2814,11 @@ struct nsStyleFilter {
bool SetURL(mozilla::css::URLValue* aValue);
const mozilla::StyleSimpleShadow& GetDropShadow() const {
nsCSSShadowArray* GetDropShadow() const {
NS_ASSERTION(mType == NS_STYLE_FILTER_DROP_SHADOW, "wrong filter type");
return mDropShadow;
}
void SetDropShadow(const mozilla::StyleSimpleShadow&);
void SetDropShadow(nsCSSShadowArray* aDropShadow);
private:
void ReleaseRef();
@ -2696,7 +2827,7 @@ struct nsStyleFilter {
nsStyleCoord mFilterParameter; // coord, percent, factor, angle
union {
mozilla::css::URLValue* mURL;
mozilla::StyleSimpleShadow mDropShadow;
nsCSSShadowArray* mDropShadow;
};
};
@ -2753,18 +2884,9 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleEffects {
bool HasFilters() const { return !mFilters.IsEmpty(); }
bool HasBoxShadowWithInset(bool aInset) const {
for (auto& shadow : mBoxShadow.AsSpan()) {
if (shadow.inset == aInset) {
return true;
}
}
return false;
}
nsTArray<nsStyleFilter> mFilters;
mozilla::StyleOwnedSlice<mozilla::StyleBoxShadow> mBoxShadow;
nsRect mClip; // offsets from UL border edge
RefPtr<nsCSSShadowArray> mBoxShadow; // nullptr for 'none'
nsRect mClip; // offsets from UL border edge
float mOpacity;
uint8_t mClipFlags; // bitfield of NS_STYLE_CLIP_* values
uint8_t mMixBlendMode; // NS_STYLE_BLEND_*

View File

@ -35,6 +35,10 @@ inline imgIContainer* nsStyleImage::GetSubImage(uint8_t aIndex) const {
return (mCachedBIData) ? mCachedBIData->GetSubImage(aIndex) : nullptr;
}
bool nsStyleText::HasTextShadow() const { return mTextShadow; }
nsCSSShadowArray* nsStyleText::GetTextShadow() const { return mTextShadow; }
bool nsStyleText::NewlineIsSignificant(const nsTextFrame* aContextFrame) const {
NS_ASSERTION(aContextFrame->StyleText() == this, "unexpected aContextFrame");
return NewlineIsSignificantStyle() &&
@ -131,7 +135,7 @@ bool nsStyleDisplay::IsFixedPosContainingBlockForNonSVGTextFrames(
// should have the FIXPOS_CB flag set on them.
NS_ASSERTION(aStyle.StyleDisplay() == this, "unexpected aStyle");
if (mWillChange.bits & mozilla::StyleWillChangeBits_FIXPOS_CB) {
if (mWillChangeBitField & mozilla::StyleWillChangeBits_FIXPOS_CB) {
return true;
}
@ -176,7 +180,7 @@ bool nsStyleDisplay::IsAbsPosContainingBlockForNonSVGTextFrames() const {
// NOTE: Any CSS properties that influence the output of this function
// should have the ABSPOS_CB set on them.
return IsAbsolutelyPositionedStyle() || IsRelativelyPositionedStyle() ||
(mWillChange.bits & mozilla::StyleWillChangeBits_ABSPOS_CB);
(mWillChangeBitField & mozilla::StyleWillChangeBits_ABSPOS_CB);
}
bool nsStyleDisplay::IsAbsPosContainingBlock(

View File

@ -9,9 +9,11 @@
*/
#include "nsStyleTransformMatrix.h"
#include "nsCSSValue.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"
#include "nsSVGUtils.h"
#include "nsCSSKeywords.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/StyleAnimationValue.h"
#include "gfxMatrix.h"
@ -125,13 +127,39 @@ void TransformReferenceBox::Init(const nsSize& aDimensions) {
}
float ProcessTranslatePart(
const LengthPercentage& aValue, TransformReferenceBox* aRefBox,
const nsCSSValue& aValue, TransformReferenceBox* aRefBox,
TransformReferenceBox::DimensionGetter aDimensionGetter) {
return aValue.ResolveToCSSPixelsWith([&] {
return aRefBox && !aRefBox->IsEmpty()
? CSSPixel::FromAppUnits((aRefBox->*aDimensionGetter)())
: CSSCoord(0);
});
nscoord offset = 0;
float percent = 0.0f;
if (aValue.GetUnit() == eCSSUnit_Percent) {
percent = aValue.GetPercentValue();
} else if (aValue.GetUnit() == eCSSUnit_Pixel ||
aValue.GetUnit() == eCSSUnit_Number) {
// Raw numbers are treated as being pixels.
return aValue.GetFloatValue();
} else if (aValue.IsCalcUnit()) {
// We can retrieve the Calc value directly because it has been computed
// from the Servo side and set by nsCSSValue::SetCalcValue().
nsStyleCoord::CalcValue calc = aValue.GetCalcValue();
percent = calc.mPercent;
offset = calc.mLength;
} else {
// Note: The unit of nsCSSValue passed from Servo side would be number,
// pixel, percent, or eCSSUnit_Calc, so it is impossible to go into
// this branch.
MOZ_CRASH("unexpected unit in ProcessTranslatePart");
}
float translation = NSAppUnitsToFloatPixels(offset, AppUnitsPerCSSPixel());
// We want to avoid calling aDimensionGetter if there's no percentage to be
// resolved (for performance reasons - see TransformReferenceBox).
if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) {
translation +=
percent * NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
AppUnitsPerCSSPixel());
}
return translation;
}
/**
@ -141,44 +169,56 @@ float ProcessTranslatePart(
*/
/* Helper function to process a matrix entry. */
static void ProcessMatrix(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp) {
const auto& matrix = aOp.AsMatrix();
static void ProcessMatrix(Matrix4x4& aMatrix, const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 7, "Invalid array!");
gfxMatrix result;
result._11 = matrix.a;
result._12 = matrix.b;
result._21 = matrix.c;
result._22 = matrix.d;
result._31 = matrix.e;
result._32 = matrix.f;
/* Take the first four elements out of the array as floats and store
* them.
*/
result._11 = aData->Item(1).GetFloatValue();
result._12 = aData->Item(2).GetFloatValue();
result._21 = aData->Item(3).GetFloatValue();
result._22 = aData->Item(4).GetFloatValue();
/* The last two elements have their length parts stored in aDelta
* and their percent parts stored in aX[0] and aY[1].
*/
result._31 = ProcessTranslatePart(aData->Item(5), &aRefBox,
&TransformReferenceBox::Width);
result._32 = ProcessTranslatePart(aData->Item(6), &aRefBox,
&TransformReferenceBox::Height);
aMatrix = result * aMatrix;
}
static void ProcessMatrix3D(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp) {
static void ProcessMatrix3D(Matrix4x4& aMatrix, const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 17, "Invalid array!");
Matrix4x4 temp;
const auto& matrix = aOp.AsMatrix3D();
temp._11 = aData->Item(1).GetFloatValue();
temp._12 = aData->Item(2).GetFloatValue();
temp._13 = aData->Item(3).GetFloatValue();
temp._14 = aData->Item(4).GetFloatValue();
temp._21 = aData->Item(5).GetFloatValue();
temp._22 = aData->Item(6).GetFloatValue();
temp._23 = aData->Item(7).GetFloatValue();
temp._24 = aData->Item(8).GetFloatValue();
temp._31 = aData->Item(9).GetFloatValue();
temp._32 = aData->Item(10).GetFloatValue();
temp._33 = aData->Item(11).GetFloatValue();
temp._34 = aData->Item(12).GetFloatValue();
temp._44 = aData->Item(16).GetFloatValue();
temp._11 = matrix.m11;
temp._12 = matrix.m12;
temp._13 = matrix.m13;
temp._14 = matrix.m14;
temp._21 = matrix.m21;
temp._22 = matrix.m22;
temp._23 = matrix.m23;
temp._24 = matrix.m24;
temp._31 = matrix.m31;
temp._32 = matrix.m32;
temp._33 = matrix.m33;
temp._34 = matrix.m34;
temp._41 = matrix.m41;
temp._42 = matrix.m42;
temp._43 = matrix.m43;
temp._44 = matrix.m44;
temp._41 = ProcessTranslatePart(aData->Item(13), &aRefBox,
&TransformReferenceBox::Width);
temp._42 = ProcessTranslatePart(aData->Item(14), &aRefBox,
&TransformReferenceBox::Height);
temp._43 = ProcessTranslatePart(aData->Item(15), nullptr);
aMatrix = temp * aMatrix;
}
@ -276,79 +316,232 @@ class Interpolate {
}
};
/**
* Calculate 2 matrices by decomposing them with Operator.
*
* @param aMatrix1 First matrix, using CSS pixel units.
* @param aMatrix2 Second matrix, using CSS pixel units.
* @param aProgress Coefficient for the Operator.
*/
template <typename Operator>
static Matrix4x4 OperateTransformMatrix(const Matrix4x4& aMatrix1,
const Matrix4x4& aMatrix2,
double aProgress) {
// Decompose both matrices
Point3D scale1(1, 1, 1), translate1;
Point4D perspective1(0, 0, 0, 1);
gfxQuaternion rotate1;
nsStyleTransformMatrix::ShearArray shear1{0.0f, 0.0f, 0.0f};
Point3D scale2(1, 1, 1), translate2;
Point4D perspective2(0, 0, 0, 1);
gfxQuaternion rotate2;
nsStyleTransformMatrix::ShearArray shear2{0.0f, 0.0f, 0.0f};
// Check if both matrices are decomposable.
bool wasDecomposed;
Matrix matrix2d1, matrix2d2;
if (aMatrix1.Is2D(&matrix2d1) && aMatrix2.Is2D(&matrix2d2)) {
wasDecomposed =
Decompose2DMatrix(matrix2d1, scale1, shear1, rotate1, translate1) &&
Decompose2DMatrix(matrix2d2, scale2, shear2, rotate2, translate2);
} else {
wasDecomposed = Decompose3DMatrix(aMatrix1, scale1, shear1, rotate1,
translate1, perspective1) &&
Decompose3DMatrix(aMatrix2, scale2, shear2, rotate2,
translate2, perspective2);
}
// Fallback to discrete operation if one of the matrices is not decomposable.
if (!wasDecomposed) {
return Operator::operateForFallback(aMatrix1, aMatrix2, aProgress);
}
Matrix4x4 result;
// Operate each of the pieces in response to |Operator|.
Point4D perspective =
Operator::operateForPerspective(perspective1, perspective2, aProgress);
result.SetTransposedVector(3, perspective);
Point3D translate = Operator::operate(translate1, translate2, aProgress);
result.PreTranslate(translate.x, translate.y, translate.z);
Matrix4x4 rotate = Operator::operateForRotate(rotate1, rotate2, aProgress);
if (!rotate.IsIdentity()) {
result = rotate * result;
}
// TODO: Would it be better to operate these as angles?
// How do we convert back to angles?
float yzshear = Operator::operate(shear1[ShearType::YZ],
shear2[ShearType::YZ], aProgress);
if (yzshear != 0.0) {
result.SkewYZ(yzshear);
}
float xzshear = Operator::operate(shear1[ShearType::XZ],
shear2[ShearType::XZ], aProgress);
if (xzshear != 0.0) {
result.SkewXZ(xzshear);
}
float xyshear = Operator::operate(shear1[ShearType::XY],
shear2[ShearType::XY], aProgress);
if (xyshear != 0.0) {
result.SkewXY(xyshear);
}
Point3D scale = Operator::operateForScale(scale1, scale2, aProgress);
if (scale != Point3D(1.0, 1.0, 1.0)) {
result.PreScale(scale.x, scale.y, scale.z);
}
return result;
}
template <typename Operator>
static Matrix4x4 OperateTransformMatrixByServo(const Matrix4x4& aMatrix1,
const Matrix4x4& aMatrix2,
double aProgress) {
return Operator::operateByServo(aMatrix1, aMatrix2, aProgress);
}
template <typename Operator>
static void ProcessMatrixOperator(Matrix4x4& aMatrix,
const StyleTransform& aFrom,
const StyleTransform& aTo, float aProgress,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
float appUnitPerCSSPixel = AppUnitsPerCSSPixel();
Matrix4x4 matrix1 = ReadTransforms(aFrom, aRefBox, appUnitPerCSSPixel);
Matrix4x4 matrix2 = ReadTransforms(aTo, aRefBox, appUnitPerCSSPixel);
aMatrix = Operator::operateByServo(matrix1, matrix2, aProgress) * aMatrix;
MOZ_ASSERT(aData->Count() == 4, "Invalid array!");
auto readTransform = [&](const nsCSSValue& aValue) -> Matrix4x4 {
const nsCSSValueList* list = nullptr;
switch (aValue.GetUnit()) {
case eCSSUnit_List:
// For Gecko style backend.
list = aValue.GetListValue();
break;
case eCSSUnit_SharedList:
// For Servo style backend. The transform lists of interpolatematrix
// are not created on the main thread (i.e. during parallel traversal),
// and nsCSSValueList_heap is not thread safe. Therefore, we use
// nsCSSValueSharedList as a workaround.
list = aValue.GetSharedListValue()->mHead;
break;
default:
list = nullptr;
}
Matrix4x4 matrix;
if (!list) {
return matrix;
}
float appUnitPerCSSPixel = AppUnitsPerCSSPixel();
matrix = nsStyleTransformMatrix::ReadTransforms(list, aRefBox,
appUnitPerCSSPixel);
return matrix;
};
Matrix4x4 matrix1 = readTransform(aData->Item(1));
Matrix4x4 matrix2 = readTransform(aData->Item(2));
double progress = aData->Item(3).GetPercentValue();
// We cannot use GeckoComputedStyle to check if we use Servo backend because
// it could be null in Gecko. Instead, use the unit of the nsCSSValue because
// we use eCSSUnit_SharedList for Servo backend.
if (aData->Item(1).GetUnit() == eCSSUnit_SharedList) {
aMatrix =
OperateTransformMatrixByServo<Operator>(matrix1, matrix2, progress) *
aMatrix;
return;
}
aMatrix =
OperateTransformMatrix<Operator>(matrix1, matrix2, progress) * aMatrix;
}
/* Helper function to process two matrices that we need to interpolate between
*/
void ProcessInterpolateMatrix(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
const auto& args = aOp.AsInterpolateMatrix();
ProcessMatrixOperator<Interpolate>(aMatrix, args.from_list, args.to_list,
args.progress._0, aRefBox);
ProcessMatrixOperator<Interpolate>(aMatrix, aData, aRefBox);
}
void ProcessAccumulateMatrix(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp,
void ProcessAccumulateMatrix(Matrix4x4& aMatrix, const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
const auto& args = aOp.AsAccumulateMatrix();
ProcessMatrixOperator<Accumulate>(aMatrix, args.from_list, args.to_list,
args.count, aRefBox);
ProcessMatrixOperator<Accumulate>(aMatrix, aData, aRefBox);
}
/* Helper function to process a translatex function. */
static void ProcessTranslateX(Matrix4x4& aMatrix,
const LengthPercentage& aLength,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
Point3D temp;
temp.x =
ProcessTranslatePart(aLength, &aRefBox, &TransformReferenceBox::Width);
temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox,
&TransformReferenceBox::Width);
aMatrix.PreTranslate(temp);
}
/* Helper function to process a translatey function. */
static void ProcessTranslateY(Matrix4x4& aMatrix,
const LengthPercentage& aLength,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
Point3D temp;
temp.y =
ProcessTranslatePart(aLength, &aRefBox, &TransformReferenceBox::Height);
temp.y = ProcessTranslatePart(aData->Item(1), &aRefBox,
&TransformReferenceBox::Height);
aMatrix.PreTranslate(temp);
}
static void ProcessTranslateZ(Matrix4x4& aMatrix, const Length& aLength) {
static void ProcessTranslateZ(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
Point3D temp;
temp.z = aLength.ToCSSPixels();
temp.z = ProcessTranslatePart(aData->Item(1), nullptr);
aMatrix.PreTranslate(temp);
}
/* Helper function to process a translate function. */
static void ProcessTranslate(Matrix4x4& aMatrix, const LengthPercentage& aX,
const LengthPercentage& aY,
static void ProcessTranslate(Matrix4x4& aMatrix, const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 2 || aData->Count() == 3, "Invalid array!");
Point3D temp;
temp.x = ProcessTranslatePart(aX, &aRefBox, &TransformReferenceBox::Width);
temp.y = ProcessTranslatePart(aY, &aRefBox, &TransformReferenceBox::Height);
temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox,
&TransformReferenceBox::Width);
/* If we read in a Y component, set it appropriately */
if (aData->Count() == 3) {
temp.y = ProcessTranslatePart(aData->Item(2), &aRefBox,
&TransformReferenceBox::Height);
}
aMatrix.PreTranslate(temp);
}
static void ProcessTranslate3D(Matrix4x4& aMatrix, const LengthPercentage& aX,
const LengthPercentage& aY, const Length& aZ,
static void ProcessTranslate3D(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData->Count() == 4, "Invalid array!");
Point3D temp;
temp.x = ProcessTranslatePart(aX, &aRefBox, &TransformReferenceBox::Width);
temp.y = ProcessTranslatePart(aY, &aRefBox, &TransformReferenceBox::Height);
temp.z = aZ.ToCSSPixels();
temp.x = ProcessTranslatePart(aData->Item(1), &aRefBox,
&TransformReferenceBox::Width);
temp.y = ProcessTranslatePart(aData->Item(2), &aRefBox,
&TransformReferenceBox::Height);
temp.z = ProcessTranslatePart(aData->Item(3), nullptr);
aMatrix.PreTranslate(temp);
}
@ -359,123 +552,256 @@ static void ProcessScaleHelper(Matrix4x4& aMatrix, float aXScale, float aYScale,
aMatrix.PreScale(aXScale, aYScale, aZScale);
}
static void ProcessScale3D(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp) {
const auto& scale = aOp.AsScale3D();
ProcessScaleHelper(aMatrix, scale._0, scale._1, scale._2);
/* Process a scalex function. */
static void ProcessScaleX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Bad array!");
ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(), 1.0f, 1.0f);
}
/* Process a scaley function. */
static void ProcessScaleY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Bad array!");
ProcessScaleHelper(aMatrix, 1.0f, aData->Item(1).GetFloatValue(), 1.0f);
}
static void ProcessScaleZ(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Bad array!");
ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aData->Item(1).GetFloatValue());
}
static void ProcessScale3D(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 4, "Bad array!");
ProcessScaleHelper(aMatrix, aData->Item(1).GetFloatValue(),
aData->Item(2).GetFloatValue(),
aData->Item(3).GetFloatValue());
}
/* Process a scale function. */
static void ProcessScale(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
/* We either have one element or two. If we have one, it's for both X and Y.
* Otherwise it's one for each.
*/
const nsCSSValue& scaleX = aData->Item(1);
const nsCSSValue& scaleY = (aData->Count() == 2 ? scaleX : aData->Item(2));
ProcessScaleHelper(aMatrix, scaleX.GetFloatValue(), scaleY.GetFloatValue(),
1.0f);
}
/* Helper function that, given a set of angles, constructs the appropriate
* skew matrix.
*/
static void ProcessSkewHelper(Matrix4x4& aMatrix, const StyleAngle& aXAngle,
const StyleAngle& aYAngle) {
aMatrix.SkewXY(aXAngle.ToRadians(), aYAngle.ToRadians());
static void ProcessSkewHelper(Matrix4x4& aMatrix, double aXAngle,
double aYAngle) {
aMatrix.SkewXY(aXAngle, aYAngle);
}
static void ProcessRotate3D(Matrix4x4& aMatrix, float aX, float aY, float aZ,
const StyleAngle& aAngle) {
/* Function that converts a skewx transform into a matrix. */
static void ProcessSkewX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
NS_ASSERTION(aData->Count() == 2, "Bad array!");
ProcessSkewHelper(aMatrix, aData->Item(1).GetAngleValueInRadians(), 0.0);
}
/* Function that converts a skewy transform into a matrix. */
static void ProcessSkewY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
NS_ASSERTION(aData->Count() == 2, "Bad array!");
ProcessSkewHelper(aMatrix, 0.0, aData->Item(1).GetAngleValueInRadians());
}
/* Function that converts a skew transform into a matrix. */
static void ProcessSkew(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
NS_ASSERTION(aData->Count() == 2 || aData->Count() == 3, "Bad array!");
double xSkew = aData->Item(1).GetAngleValueInRadians();
double ySkew =
(aData->Count() == 2 ? 0.0 : aData->Item(2).GetAngleValueInRadians());
ProcessSkewHelper(aMatrix, xSkew, ySkew);
}
/* Function that converts a rotate transform into a matrix. */
static void ProcessRotateZ(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
double theta = aData->Item(1).GetAngleValueInRadians();
aMatrix.RotateZ(theta);
}
static void ProcessRotateX(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
double theta = aData->Item(1).GetAngleValueInRadians();
aMatrix.RotateX(theta);
}
static void ProcessRotateY(Matrix4x4& aMatrix, const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
double theta = aData->Item(1).GetAngleValueInRadians();
aMatrix.RotateY(theta);
}
static void ProcessRotate3D(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 5, "Invalid array!");
double theta = aData->Item(4).GetAngleValueInRadians();
float x = aData->Item(1).GetFloatValue();
float y = aData->Item(2).GetFloatValue();
float z = aData->Item(3).GetFloatValue();
Matrix4x4 temp;
temp.SetRotateAxisAngle(aX, aY, aZ, aAngle.ToRadians());
temp.SetRotateAxisAngle(x, y, z, theta);
aMatrix = temp * aMatrix;
}
static void ProcessPerspective(Matrix4x4& aMatrix, const Length& aLength) {
float depth = aLength.ToCSSPixels();
static void ProcessPerspective(Matrix4x4& aMatrix,
const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Count() == 2, "Invalid array!");
float depth = ProcessTranslatePart(aData->Item(1), nullptr);
ApplyPerspectiveToMatrix(aMatrix, depth);
}
/**
* SetToTransformFunction is essentially a giant switch statement that fans
* out to many smaller helper functions.
*/
static void MatrixForTransformFunction(Matrix4x4& aMatrix,
const StyleTransformOperation& aOp,
const nsCSSValue::Array* aData,
TransformReferenceBox& aRefBox) {
MOZ_ASSERT(aData, "Why did you want to get data from a null array?");
/* Get the keyword for the transform. */
switch (aOp.tag) {
case StyleTransformOperation::Tag::TranslateX:
ProcessTranslateX(aMatrix, aOp.AsTranslateX(), aRefBox);
switch (TransformFunctionOf(aData)) {
case eCSSKeyword_translatex:
ProcessTranslateX(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::TranslateY:
ProcessTranslateY(aMatrix, aOp.AsTranslateY(), aRefBox);
case eCSSKeyword_translatey:
ProcessTranslateY(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::TranslateZ:
ProcessTranslateZ(aMatrix, aOp.AsTranslateZ());
case eCSSKeyword_translatez:
ProcessTranslateZ(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Translate:
ProcessTranslate(aMatrix, aOp.AsTranslate()._0, aOp.AsTranslate()._1,
aRefBox);
case eCSSKeyword_translate:
ProcessTranslate(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::Translate3D:
return ProcessTranslate3D(aMatrix, aOp.AsTranslate3D()._0,
aOp.AsTranslate3D()._1, aOp.AsTranslate3D()._2,
aRefBox);
case eCSSKeyword_translate3d:
ProcessTranslate3D(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::ScaleX:
ProcessScaleHelper(aMatrix, aOp.AsScaleX(), 1.0f, 1.0f);
case eCSSKeyword_scalex:
ProcessScaleX(aMatrix, aData);
break;
case StyleTransformOperation::Tag::ScaleY:
ProcessScaleHelper(aMatrix, 1.0f, aOp.AsScaleY(), 1.0f);
case eCSSKeyword_scaley:
ProcessScaleY(aMatrix, aData);
break;
case StyleTransformOperation::Tag::ScaleZ:
ProcessScaleHelper(aMatrix, 1.0f, 1.0f, aOp.AsScaleZ());
case eCSSKeyword_scalez:
ProcessScaleZ(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Scale:
ProcessScaleHelper(aMatrix, aOp.AsScale()._0, aOp.AsScale()._1, 1.0f);
case eCSSKeyword_scale:
ProcessScale(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Scale3D:
ProcessScale3D(aMatrix, aOp);
case eCSSKeyword_scale3d:
ProcessScale3D(aMatrix, aData);
break;
case StyleTransformOperation::Tag::SkewX:
ProcessSkewHelper(aMatrix, aOp.AsSkewX(), StyleAngle::Zero());
case eCSSKeyword_skewx:
ProcessSkewX(aMatrix, aData);
break;
case StyleTransformOperation::Tag::SkewY:
ProcessSkewHelper(aMatrix, StyleAngle::Zero(), aOp.AsSkewY());
case eCSSKeyword_skewy:
ProcessSkewY(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Skew:
ProcessSkewHelper(aMatrix, aOp.AsSkew()._0, aOp.AsSkew()._1);
case eCSSKeyword_skew:
ProcessSkew(aMatrix, aData);
break;
case StyleTransformOperation::Tag::RotateX:
aMatrix.RotateX(aOp.AsRotateX().ToRadians());
case eCSSKeyword_rotatex:
ProcessRotateX(aMatrix, aData);
break;
case StyleTransformOperation::Tag::RotateY:
aMatrix.RotateY(aOp.AsRotateY().ToRadians());
case eCSSKeyword_rotatey:
ProcessRotateY(aMatrix, aData);
break;
case StyleTransformOperation::Tag::RotateZ:
aMatrix.RotateZ(aOp.AsRotateZ().ToRadians());
case eCSSKeyword_rotatez:
MOZ_FALLTHROUGH;
case eCSSKeyword_rotate:
ProcessRotateZ(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Rotate:
aMatrix.RotateZ(aOp.AsRotate().ToRadians());
case eCSSKeyword_rotate3d:
ProcessRotate3D(aMatrix, aData);
break;
case StyleTransformOperation::Tag::Rotate3D:
ProcessRotate3D(aMatrix, aOp.AsRotate3D()._0, aOp.AsRotate3D()._1,
aOp.AsRotate3D()._2, aOp.AsRotate3D()._3);
case eCSSKeyword_matrix:
ProcessMatrix(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::Matrix:
ProcessMatrix(aMatrix, aOp);
case eCSSKeyword_matrix3d:
ProcessMatrix3D(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::Matrix3D:
ProcessMatrix3D(aMatrix, aOp);
case eCSSKeyword_interpolatematrix:
ProcessMatrixOperator<Interpolate>(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::InterpolateMatrix:
ProcessInterpolateMatrix(aMatrix, aOp, aRefBox);
case eCSSKeyword_accumulatematrix:
ProcessMatrixOperator<Accumulate>(aMatrix, aData, aRefBox);
break;
case StyleTransformOperation::Tag::AccumulateMatrix:
ProcessAccumulateMatrix(aMatrix, aOp, aRefBox);
break;
case StyleTransformOperation::Tag::Perspective:
ProcessPerspective(aMatrix, aOp.AsPerspective());
case eCSSKeyword_perspective:
ProcessPerspective(aMatrix, aData);
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown transform function!");
}
}
Matrix4x4 ReadTransforms(const StyleTransform& aTransform,
/**
* Return the transform function, as an nsCSSKeyword, for the given
* nsCSSValue::Array from a transform list.
*/
nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData) {
MOZ_ASSERT(aData->Item(0).GetUnit() == eCSSUnit_Enumerated);
return aData->Item(0).GetKeywordValue();
}
void SetIdentityMatrix(nsCSSValue::Array* aMatrix) {
MOZ_ASSERT(aMatrix, "aMatrix should be non-null");
nsCSSKeyword tfunc = TransformFunctionOf(aMatrix);
MOZ_ASSERT(tfunc == eCSSKeyword_matrix || tfunc == eCSSKeyword_matrix3d,
"Only accept matrix and matrix3d");
if (tfunc == eCSSKeyword_matrix) {
MOZ_ASSERT(aMatrix->Count() == 7, "Invalid matrix");
Matrix m;
for (size_t i = 0; i < 6; ++i) {
aMatrix->Item(i + 1).SetFloatValue(m.components[i], eCSSUnit_Number);
}
return;
}
MOZ_ASSERT(aMatrix->Count() == 17, "Invalid matrix3d");
Matrix4x4 m;
for (size_t i = 0; i < 16; ++i) {
aMatrix->Item(i + 1).SetFloatValue(m.components[i], eCSSUnit_Number);
}
}
static void ReadTransformsImpl(Matrix4x4& aMatrix, const nsCSSValueList* aList,
TransformReferenceBox& aRefBox) {
for (const nsCSSValueList* curr = aList; curr != nullptr;
curr = curr->mNext) {
const nsCSSValue& currElem = curr->mValue;
if (currElem.GetUnit() != eCSSUnit_Function) {
NS_ASSERTION(currElem.GetUnit() == eCSSUnit_None && !aList->mNext,
"stream should either be a list of functions or a "
"lone None");
continue;
}
NS_ASSERTION(currElem.GetArrayValue()->Count() >= 1,
"Incoming function is too short!");
/* Read in a single transform matrix. */
MatrixForTransformFunction(aMatrix, currElem.GetArrayValue(), aRefBox);
}
}
Matrix4x4 ReadTransforms(const nsCSSValueList* aList,
TransformReferenceBox& aRefBox,
float aAppUnitsPerMatrixUnit) {
Matrix4x4 result;
for (const StyleTransformOperation& op : aTransform.Operations()) {
MatrixForTransformFunction(result, op, aRefBox);
}
ReadTransformsImpl(result, aList, aRefBox);
float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
result.PreScale(1 / scale, 1 / scale, 1 / scale);
@ -484,68 +810,16 @@ Matrix4x4 ReadTransforms(const StyleTransform& aTransform,
return result;
}
static void ProcessTranslate(Matrix4x4& aMatrix,
const StyleTranslate& aTranslate,
TransformReferenceBox& aRefBox) {
switch (aTranslate.tag) {
case StyleTranslate::Tag::None:
return;
case StyleTranslate::Tag::Translate:
return ProcessTranslate(aMatrix, aTranslate.AsTranslate()._0,
aTranslate.AsTranslate()._1, aRefBox);
case StyleTranslate::Tag::Translate3D:
return ProcessTranslate3D(aMatrix, aTranslate.AsTranslate3D()._0,
aTranslate.AsTranslate3D()._1,
aTranslate.AsTranslate3D()._2, aRefBox);
default:
MOZ_ASSERT_UNREACHABLE("Huh?");
}
}
static void ProcessRotate(Matrix4x4& aMatrix, const StyleRotate& aRotate,
TransformReferenceBox& aRefBox) {
switch (aRotate.tag) {
case StyleRotate::Tag::None:
return;
case StyleRotate::Tag::Rotate:
aMatrix.RotateZ(aRotate.AsRotate().ToRadians());
return;
case StyleRotate::Tag::Rotate3D:
return ProcessRotate3D(aMatrix, aRotate.AsRotate3D()._0,
aRotate.AsRotate3D()._1, aRotate.AsRotate3D()._2,
aRotate.AsRotate3D()._3);
default:
MOZ_ASSERT_UNREACHABLE("Huh?");
}
}
static void ProcessScale(Matrix4x4& aMatrix, const StyleScale& aScale,
TransformReferenceBox& aRefBox) {
switch (aScale.tag) {
case StyleScale::Tag::None:
return;
case StyleScale::Tag::Scale:
return ProcessScaleHelper(aMatrix, aScale.AsScale()._0,
aScale.AsScale()._1, 1.0f);
case StyleScale::Tag::Scale3D:
return ProcessScaleHelper(aMatrix, aScale.AsScale3D()._0,
aScale.AsScale3D()._1, aScale.AsScale3D()._2);
default:
MOZ_ASSERT_UNREACHABLE("Huh?");
}
}
Matrix4x4 ReadTransforms(const StyleTranslate& aTranslate,
const StyleRotate& aRotate, const StyleScale& aScale,
Matrix4x4 ReadTransforms(const nsCSSValueList* aIndividualTransforms,
const Maybe<MotionPathData>& aMotion,
const StyleTransform& aTransform,
const nsCSSValueList* aTransform,
TransformReferenceBox& aRefBox,
float aAppUnitsPerMatrixUnit) {
Matrix4x4 result;
ProcessTranslate(result, aTranslate, aRefBox);
ProcessRotate(result, aRotate, aRefBox);
ProcessScale(result, aScale, aRefBox);
if (aIndividualTransforms) {
ReadTransformsImpl(result, aIndividualTransforms, aRefBox);
}
if (aMotion.isSome()) {
// Create the equivalent translate and rotate function, according to the
@ -557,8 +831,8 @@ Matrix4x4 ReadTransforms(const StyleTranslate& aTranslate,
}
}
for (const StyleTransformOperation& op : aTransform.Operations()) {
MatrixForTransformFunction(result, op, aRefBox);
if (aTransform) {
ReadTransformsImpl(result, aTransform, aRefBox);
}
float scale = float(AppUnitsPerCSSPixel()) / aAppUnitsPerMatrixUnit;
@ -775,7 +1049,6 @@ bool Decompose3DMatrix(const Matrix4x4& aMatrix, Point3D& aScale,
if (local[3][3] == 0) {
return false;
}
/* Normalize the matrix */
local.Normalize();
@ -861,4 +1134,41 @@ bool Decompose3DMatrix(const Matrix4x4& aMatrix, Point3D& aScale,
return true;
}
Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray) {
MOZ_ASSERT(aArray && TransformFunctionOf(aArray) == eCSSKeyword_matrix &&
aArray->Count() == 7);
Matrix m(aArray->Item(1).GetFloatValue(), aArray->Item(2).GetFloatValue(),
aArray->Item(3).GetFloatValue(), aArray->Item(4).GetFloatValue(),
aArray->Item(5).GetFloatValue(), aArray->Item(6).GetFloatValue());
return m;
}
Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray) {
MOZ_ASSERT(aArray && TransformFunctionOf(aArray) == eCSSKeyword_matrix3d &&
aArray->Count() == 17);
gfx::Float array[16];
for (size_t i = 0; i < 16; ++i) {
array[i] = aArray->Item(i + 1).GetFloatValue();
}
Matrix4x4 m(array);
return m;
}
Size GetScaleValue(const nsCSSValueSharedList* aList,
const nsIFrame* aForFrame) {
MOZ_ASSERT(aList && aList->mHead);
MOZ_ASSERT(aForFrame);
TransformReferenceBox refBox(aForFrame);
Matrix4x4 transform = ReadTransforms(
aList->mHead, refBox, aForFrame->PresContext()->AppUnitsPerDevPixel());
Matrix transform2d;
bool canDraw2D = transform.CanDraw2D(&transform2d);
if (!canDraw2D) {
return Size();
}
return transform2d.ScaleFactors(true);
}
} // namespace nsStyleTransformMatrix

View File

@ -14,6 +14,7 @@
#include "gfxPoint.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/EnumeratedArray.h"
#include "nsCSSValue.h"
#include "nsSize.h"
#include <limits>
@ -143,37 +144,46 @@ class MOZ_STACK_CLASS TransformReferenceBox final {
bool mIsCached;
};
/**
* Return the transform function, as an nsCSSKeyword, for the given
* nsCSSValue::Array from a transform list.
*/
nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
void SetIdentityMatrix(nsCSSValue::Array* aMatrix);
float ProcessTranslatePart(
const mozilla::LengthPercentage& aValue, TransformReferenceBox* aRefBox,
const nsCSSValue& aValue, TransformReferenceBox* aRefBox,
TransformReferenceBox::DimensionGetter aDimensionGetter = nullptr);
void ProcessInterpolateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
const mozilla::StyleTransformOperation& aOp,
const nsCSSValue::Array* aData,
TransformReferenceBox& aBounds);
void ProcessAccumulateMatrix(mozilla::gfx::Matrix4x4& aMatrix,
const mozilla::StyleTransformOperation& aOp,
const nsCSSValue::Array* aData,
TransformReferenceBox& aBounds);
/**
* Given a StyleTransform containing transform functions, returns a matrix
* containing the value of those functions.
* Given an nsCSSValueList containing -moz-transform functions,
* returns a matrix containing the value of those functions.
*
* @param aList the transform operation list.
* @param aData The nsCSSValueList containing the transform functions
* @param aBounds The frame's bounding rectangle.
* @param aAppUnitsPerMatrixUnit The number of app units per device pixel.
*
* eCSSUnit_Pixel (as they are in an StyleAnimationValue)
*/
mozilla::gfx::Matrix4x4 ReadTransforms(const mozilla::StyleTransform& aList,
mozilla::gfx::Matrix4x4 ReadTransforms(const nsCSSValueList* aList,
TransformReferenceBox& aBounds,
float aAppUnitsPerMatrixUnit);
// Generate the gfx::Matrix for CSS Transform Module Level 2.
// https://drafts.csswg.org/css-transforms-2/#ctm
mozilla::gfx::Matrix4x4 ReadTransforms(
const mozilla::StyleTranslate&, const mozilla::StyleRotate&,
const mozilla::StyleScale&,
const nsCSSValueList* aIndividualTransforms,
const mozilla::Maybe<mozilla::MotionPathData>& aMotion,
const mozilla::StyleTransform&, TransformReferenceBox& aRefBox,
const nsCSSValueList* aTransform, TransformReferenceBox& aRefBox,
float aAppUnitsPerMatrixUnit);
/**
@ -213,6 +223,11 @@ bool Decompose3DMatrix(const mozilla::gfx::Matrix4x4& aMatrix,
mozilla::gfx::Point3D& aTranslate,
mozilla::gfx::Point4D& aPerspective);
mozilla::gfx::Matrix CSSValueArrayTo2DMatrix(nsCSSValue::Array* aArray);
mozilla::gfx::Matrix4x4 CSSValueArrayTo3DMatrix(nsCSSValue::Array* aArray);
mozilla::gfx::Size GetScaleValue(const nsCSSValueSharedList* aList,
const nsIFrame* aForFrame);
} // namespace nsStyleTransformMatrix
#endif

View File

@ -45,21 +45,21 @@ void SVGImageContext::MaybeStoreContextPaint(Maybe<SVGImageContext>& aContext,
RefPtr<SVGEmbeddingContextPaint> contextPaint =
new SVGEmbeddingContextPaint();
if ((style->mMozContextProperties.bits & StyleContextPropertyBits_FILL) &&
if ((style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_FILL) &&
style->mFill.Type() == eStyleSVGPaintType_Color) {
haveContextPaint = true;
contextPaint->SetFill(style->mFill.GetColor(aFromComputedStyle));
}
if ((style->mMozContextProperties.bits & StyleContextPropertyBits_STROKE) &&
if ((style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_STROKE) &&
style->mStroke.Type() == eStyleSVGPaintType_Color) {
haveContextPaint = true;
contextPaint->SetStroke(style->mStroke.GetColor(aFromComputedStyle));
}
if (style->mMozContextProperties.bits & StyleContextPropertyBits_FILL_OPACITY) {
if (style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY) {
haveContextPaint = true;
contextPaint->SetFillOpacity(style->mFillOpacity);
}
if (style->mMozContextProperties.bits & StyleContextPropertyBits_STROKE_OPACITY) {
if (style->mContextPropsBits & NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY) {
haveContextPaint = true;
contextPaint->SetStrokeOpacity(style->mStrokeOpacity);
}

View File

@ -169,21 +169,26 @@ nsresult nsCSSFilterInstance::SetAttributesForContrast(
nsresult nsCSSFilterInstance::SetAttributesForDropShadow(
FilterPrimitiveDescription& aDescr) {
const auto& shadow = mFilter.GetDropShadow();
nsCSSShadowArray* shadows = mFilter.GetDropShadow();
if (!shadows || shadows->Length() != 1) {
MOZ_ASSERT_UNREACHABLE("Exactly one drop shadow should have been parsed.");
return NS_ERROR_FAILURE;
}
DropShadowAttributes atts;
nsCSSShadowItem* shadow = shadows->ShadowAt(0);
// Set drop shadow blur radius.
Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow.blur.ToAppUnits());
Size radiusInFilterSpace = BlurRadiusToFilterSpace(shadow->mRadius);
atts.mStdDeviation = radiusInFilterSpace;
// Set offset.
IntPoint offsetInFilterSpace = OffsetToFilterSpace(
shadow.horizontal.ToAppUnits(), shadow.vertical.ToAppUnits());
IntPoint offsetInFilterSpace =
OffsetToFilterSpace(shadow->mXOffset, shadow->mYOffset);
atts.mOffset = offsetInFilterSpace;
// Set color. If unspecified, use the CSS color property.
nscolor shadowColor = shadow.color.CalcColor(mShadowFallbackColor);
nscolor shadowColor = shadow->mColor.CalcColor(mShadowFallbackColor);
atts.mColor = ToAttributeColor(shadowColor);
aDescr.Attributes() = AsVariant(std::move(atts));

View File

@ -1724,9 +1724,12 @@ gfxMatrix nsSVGUtils::GetTransformMatrixInUserSpace(const nsIFrame* aFrame) {
if (properties.HasTransform()) {
trans = nsStyleTransformMatrix::ReadTransforms(
properties.mTranslate, properties.mRotate, properties.mScale,
properties.mMotion, properties.mTransform, refBox,
AppUnitsPerCSSPixel());
properties.mIndividualTransformList
? properties.mIndividualTransformList->mHead
: nullptr,
properties.mMotion,
properties.mTransformList ? properties.mTransformList->mHead : nullptr,
refBox, AppUnitsPerCSSPixel());
} else {
trans = Matrix4x4::From2D(svgTransform);
}

View File

@ -444,7 +444,7 @@ void nsTableCellFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
DO_GLOBAL_REFLOW_COUNT_DSP("nsTableCellFrame");
if (ShouldPaintBordersAndBackgrounds()) {
// display outset box-shadows if we need to.
bool hasBoxShadow = !StyleEffects()->mBoxShadow.IsEmpty();
bool hasBoxShadow = !!StyleEffects()->mBoxShadow;
if (hasBoxShadow) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowOuter>(
aBuilder, this);

View File

@ -1410,7 +1410,7 @@ void nsTableFrame::DisplayGenericTablePart(
// when we're not the whole table?
// Paint the outset box-shadows for the table frames
if (!aFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
if (aFrame->StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowOuter>(
aBuilder, aFrame);
}
@ -1483,7 +1483,7 @@ void nsTableFrame::DisplayGenericTablePart(
// when we're not the whole table?
// Paint the inset box-shadows for the table frames
if (!aFrame->StyleEffects()->mBoxShadow.IsEmpty()) {
if (aFrame->StyleEffects()->mBoxShadow) {
aLists.BorderBackground()->AppendNewToTop<nsDisplayBoxShadowInner>(
aBuilder, aFrame);
}

View File

@ -948,7 +948,7 @@ nsTextBoxFrame::DoXULLayout(nsBoxLayoutState& aBoxLayoutState) {
visualBounds.UnionRect(scrollBounds, textRect);
nsOverflowAreas overflow(visualBounds, scrollBounds);
if (textStyle->HasTextShadow()) {
if (textStyle->mTextShadow) {
// text-shadow extends our visual but not scrollable bounds
nsRect& vis = overflow.VisualOverflow();
vis.UnionRect(vis,
@ -960,7 +960,7 @@ nsTextBoxFrame::DoXULLayout(nsBoxLayoutState& aBoxLayoutState) {
}
nsRect nsTextBoxFrame::GetComponentAlphaBounds() const {
if (StyleText()->HasTextShadow()) {
if (StyleText()->mTextShadow) {
return GetVisualOverflowRectRelativeToSelf();
}
return mTextDrawRect;

View File

@ -19,6 +19,7 @@ use selectors::parser::SelectorParseErrorKind;
use std::fmt::{self, Write};
use std::mem;
use std::num::Wrapping;
use std::ops::Range;
use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
use style_traits::{StyleParseErrorKind, ToCss};
@ -260,7 +261,7 @@ counter_style_descriptors! {
"suffix" suffix / set_suffix [_]: Symbol,
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
"range" range / set_range [_]: CounterRanges,
"range" range / set_range [_]: Ranges,
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
"pad" pad / set_pad [_]: Pad,
@ -370,7 +371,7 @@ impl Parse for System {
"additive" => Ok(System::Additive),
"fixed" => {
let first_symbol_value = input.try(|i| Integer::parse(context, i)).ok();
Ok(System::Fixed { first_symbol_value })
Ok(System::Fixed { first_symbol_value: first_symbol_value })
}
"extends" => {
let other = parse_counter_style_name(input)?;
@ -408,10 +409,11 @@ impl ToCss for System {
}
/// <https://drafts.csswg.org/css-counter-styles/#typedef-symbol>
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem, MallocSizeOf)]
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)]
pub enum Symbol {
/// <string>
String(crate::OwnedStr),
String(String),
/// <custom-ident>
Ident(CustomIdent),
// Not implemented:
@ -426,7 +428,7 @@ impl Parse for Symbol {
) -> Result<Self, ParseError<'i>> {
let location = input.current_source_location();
match *input.next()? {
Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned().into())),
Token::QuotedString(ref s) => Ok(Symbol::String(s.as_ref().to_owned())),
Token::Ident(ref s) => Ok(Symbol::Ident(CustomIdent::from_ident(location, s, &[])?)),
ref t => Err(location.new_unexpected_token_error(t.clone())),
}
@ -460,26 +462,13 @@ impl Parse for Negative {
}
}
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
#[derive(Clone, Debug, ToShmem, ToCss)]
pub struct CounterRange {
/// The start of the range.
pub start: CounterBound,
/// The end of the range.
pub end: CounterBound,
}
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-range>
///
/// Empty represents 'auto'
#[derive(Clone, Debug, ToShmem, ToCss)]
#[css(comma)]
pub struct CounterRanges(
#[css(iterable, if_empty = "auto")]
pub crate::OwnedSlice<CounterRange>,
);
/// Empty Vec represents 'auto'
#[derive(Clone, Debug, ToShmem)]
pub struct Ranges(pub Vec<Range<CounterBound>>);
/// A bound found in `CounterRanges`.
/// A bound found in `Ranges`.
#[derive(Clone, Copy, Debug, ToCss, ToShmem)]
pub enum CounterBound {
/// An integer bound.
@ -488,7 +477,7 @@ pub enum CounterBound {
Infinite,
}
impl Parse for CounterRanges {
impl Parse for Ranges {
fn parse<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
@ -497,25 +486,25 @@ impl Parse for CounterRanges {
.try(|input| input.expect_ident_matching("auto"))
.is_ok()
{
return Ok(CounterRanges(Default::default()));
Ok(Ranges(Vec::new()))
} else {
input
.parse_comma_separated(|input| {
let opt_start = parse_bound(context, input)?;
let opt_end = parse_bound(context, input)?;
if let (CounterBound::Integer(start), CounterBound::Integer(end)) =
(opt_start, opt_end)
{
if start > end {
return Err(
input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
);
}
}
Ok(opt_start..opt_end)
})
.map(Ranges)
}
let ranges = input.parse_comma_separated(|input| {
let start = parse_bound(context, input)?;
let end = parse_bound(context, input)?;
if let (CounterBound::Integer(start), CounterBound::Integer(end)) =
(start, end)
{
if start > end {
return Err(
input.new_custom_error(StyleParseErrorKind::UnspecifiedError)
);
}
}
Ok(CounterRange { start, end })
})?;
Ok(CounterRanges(ranges.into()))
}
}
@ -530,6 +519,34 @@ fn parse_bound<'i, 't>(
Ok(CounterBound::Infinite)
}
impl ToCss for Ranges {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
let mut iter = self.0.iter();
if let Some(first) = iter.next() {
range_to_css(first, dest)?;
for item in iter {
dest.write_str(", ")?;
range_to_css(item, dest)?;
}
Ok(())
} else {
dest.write_str("auto")
}
}
}
fn range_to_css<W>(range: &Range<CounterBound>, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
range.start.to_css(dest)?;
dest.write_char(' ')?;
range.end.to_css(dest)
}
/// <https://drafts.csswg.org/css-counter-styles/#counter-style-pad>
#[derive(Clone, Debug, ToCss, ToShmem)]
pub struct Pad(pub Integer, pub Symbol);
@ -555,13 +572,14 @@ impl Parse for Fallback {
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
Ok(Fallback(parse_counter_style_name(input)?))
parse_counter_style_name(input).map(Fallback)
}
}
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-symbols>
#[derive(Clone, Debug, Eq, PartialEq, MallocSizeOf, ToComputedValue, ToCss, ToShmem)]
pub struct Symbols(#[css(iterable)] pub crate::OwnedSlice<Symbol>);
#[cfg_attr(feature = "gecko", derive(MallocSizeOf))]
#[derive(Clone, Debug, Eq, PartialEq, ToComputedValue, ToCss, ToShmem)]
pub struct Symbols(#[css(iterable)] pub Vec<Symbol>);
impl Parse for Symbols {
fn parse<'i, 't>(
@ -569,20 +587,23 @@ impl Parse for Symbols {
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
let mut symbols = Vec::new();
while let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
symbols.push(s);
loop {
if let Ok(s) = input.try(|input| Symbol::parse(context, input)) {
symbols.push(s)
} else {
if symbols.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
} else {
return Ok(Symbols(symbols));
}
}
}
if symbols.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(Symbols(symbols.into()))
}
}
/// <https://drafts.csswg.org/css-counter-styles/#descdef-counter-style-additive-symbols>
#[derive(Clone, Debug, ToCss, ToShmem)]
#[css(comma)]
pub struct AdditiveSymbols(#[css(iterable)] pub crate::OwnedSlice<AdditiveTuple>);
pub struct AdditiveSymbols(pub Vec<AdditiveTuple>);
impl Parse for AdditiveSymbols {
fn parse<'i, 't>(
@ -597,7 +618,7 @@ impl Parse for AdditiveSymbols {
{
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(AdditiveSymbols(tuples.into()))
Ok(AdditiveSymbols(tuples))
}
}
@ -622,7 +643,10 @@ impl Parse for AdditiveTuple {
let symbol = input.try(|input| Symbol::parse(context, input));
let weight = Integer::parse_non_negative(context, input)?;
let symbol = symbol.or_else(|_| Symbol::parse(context, input))?;
Ok(Self { weight, symbol })
Ok(AdditiveTuple {
weight: weight,
symbol: symbol,
})
}
}

View File

@ -23,6 +23,7 @@ use crate::gecko_bindings::structs::RawServoMediaRule;
use crate::gecko_bindings::structs::RawServoMozDocumentRule;
use crate::gecko_bindings::structs::RawServoNamespaceRule;
use crate::gecko_bindings::structs::RawServoPageRule;
use crate::gecko_bindings::structs::RawServoQuotes;
use crate::gecko_bindings::structs::RawServoStyleRule;
use crate::gecko_bindings::structs::RawServoStyleSheetContents;
use crate::gecko_bindings::structs::RawServoSupportsRule;
@ -39,6 +40,7 @@ use crate::stylesheets::{NamespaceRule, PageRule};
use crate::stylesheets::{StyleRule, StylesheetContents, SupportsRule};
use servo_arc::{Arc, ArcBorrow};
use std::{mem, ptr};
use values::computed::QuotePair;
macro_rules! impl_arc_ffi {
($servo_type:ty => $gecko_type:ty[$addref:ident, $release:ident]) => {
@ -113,6 +115,9 @@ impl_arc_ffi!(Locked<CounterStyleRule> => RawServoCounterStyleRule
impl_arc_ffi!(CssUrlData => RawServoCssUrlData
[Servo_CssUrlData_AddRef, Servo_CssUrlData_Release]);
impl_arc_ffi!(Box<[QuotePair]> => RawServoQuotes
[Servo_Quotes_AddRef, Servo_Quotes_Release]);
// ComputedStyle is not an opaque type on any side of FFI.
// This means that doing the HasArcFFI type trick is actually unsound,
// since it gives us a way to construct an Arc<ComputedStyle> from

View File

@ -17,6 +17,7 @@ pub mod media_queries;
pub mod profiler;
pub mod pseudo_element;
pub mod restyle_damage;
pub mod rules;
pub mod selector_parser;
pub mod snapshot;
pub mod snapshot_helpers;

View File

@ -0,0 +1,135 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Bindings for CSS Rule objects
use crate::counter_style::{self, CounterBound};
use crate::gecko_bindings::structs::{self, nsCSSValue};
use crate::gecko_bindings::sugar::ns_css_value::ToNsCssValue;
impl<'a> ToNsCssValue for &'a counter_style::System {
fn convert(self, nscssvalue: &mut nsCSSValue) {
use crate::counter_style::System::*;
match *self {
Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32),
Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32),
Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
Additive => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ADDITIVE as i32),
Fixed {
ref first_symbol_value,
} => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_FIXED as i32);
b.set_integer(first_symbol_value.map_or(1, |v| v.value()));
nscssvalue.set_pair(&a, &b);
},
Extends(ref other) => {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_EXTENDS as i32);
b.set_atom_ident(other.0.clone());
nscssvalue.set_pair(&a, &b);
},
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Negative {
fn convert(self, nscssvalue: &mut nsCSSValue) {
if let Some(ref second) = self.1 {
let mut a = nsCSSValue::null();
let mut b = nsCSSValue::null();
a.set_from(&self.0);
b.set_from(second);
nscssvalue.set_pair(&a, &b);
} else {
nscssvalue.set_from(&self.0)
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Symbol {
fn convert(self, nscssvalue: &mut nsCSSValue) {
match *self {
counter_style::Symbol::String(ref s) => nscssvalue.set_string(s),
counter_style::Symbol::Ident(ref s) => nscssvalue.set_ident_from_atom(&s.0),
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Ranges {
fn convert(self, nscssvalue: &mut nsCSSValue) {
if self.0.is_empty() {
nscssvalue.set_auto();
} else {
nscssvalue.set_pair_list(self.0.iter().map(|range| {
fn set_bound(bound: CounterBound, nscssvalue: &mut nsCSSValue) {
if let CounterBound::Integer(finite) = bound {
nscssvalue.set_integer(finite.value())
} else {
nscssvalue.set_enum(structs::NS_STYLE_COUNTER_RANGE_INFINITE as i32)
}
}
let mut start = nsCSSValue::null();
let mut end = nsCSSValue::null();
set_bound(range.start, &mut start);
set_bound(range.end, &mut end);
(start, end)
}));
}
}
}
impl<'a> ToNsCssValue for &'a counter_style::Pad {
fn convert(self, nscssvalue: &mut nsCSSValue) {
let mut min_length = nsCSSValue::null();
let mut pad_with = nsCSSValue::null();
min_length.set_integer(self.0.value());
pad_with.set_from(&self.1);
nscssvalue.set_pair(&min_length, &pad_with);
}
}
impl<'a> ToNsCssValue for &'a counter_style::Fallback {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_atom_ident(self.0 .0.clone())
}
}
impl<'a> ToNsCssValue for &'a counter_style::Symbols {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_list(self.0.iter().map(|item| {
let mut value = nsCSSValue::null();
value.set_from(item);
value
}));
}
}
impl<'a> ToNsCssValue for &'a counter_style::AdditiveSymbols {
fn convert(self, nscssvalue: &mut nsCSSValue) {
nscssvalue.set_pair_list(self.0.iter().map(|tuple| {
let mut weight = nsCSSValue::null();
let mut symbol = nsCSSValue::null();
weight.set_integer(tuple.weight.value());
symbol.set_from(&tuple.symbol);
(weight, symbol)
}));
}
}
impl<'a> ToNsCssValue for &'a counter_style::SpeakAs {
fn convert(self, nscssvalue: &mut nsCSSValue) {
use crate::counter_style::SpeakAs::*;
match *self {
Auto => nscssvalue.set_auto(),
Bullets => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_BULLETS as i32),
Numbers => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_NUMBERS as i32),
Words => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SPEAKAS_WORDS as i32),
Other(ref other) => nscssvalue.set_atom_ident(other.0.clone()),
}
}
}

View File

@ -288,7 +288,7 @@ impl CounterStyleOrNone {
.0
.iter()
.map(|symbol| match *symbol {
Symbol::String(ref s) => nsCStr::from(&**s),
Symbol::String(ref s) => nsCStr::from(s),
Symbol::Ident(_) => unreachable!("Should not have identifier in symbols()"),
})
.collect();
@ -333,7 +333,7 @@ impl CounterStyleOrNone {
let symbol_type = SymbolsType::from_gecko_keyword(anonymous.mSystem as u32);
let symbols = symbols
.iter()
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string().into()))
.map(|gecko_symbol| Symbol::String(gecko_symbol.to_string()))
.collect();
Either::First(CounterStyleOrNone::Symbols(symbol_type, Symbols(symbols)))
}

View File

@ -6,6 +6,9 @@
mod ns_com_ptr;
mod ns_compatibility;
mod ns_css_shadow_array;
mod ns_css_shadow_item;
pub mod ns_css_value;
mod ns_style_auto_array;
pub mod ns_style_coord;
mod ns_t_array;

View File

@ -0,0 +1,78 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Rust helpers for Gecko's `nsCSSShadowArray`.
use crate::gecko_bindings::bindings::Gecko_AddRefCSSShadowArrayArbitraryThread;
use crate::gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use crate::gecko_bindings::bindings::Gecko_ReleaseCSSShadowArrayArbitraryThread;
use crate::gecko_bindings::structs::{nsCSSShadowArray, nsCSSShadowItem, RefPtr};
use std::ops::{Deref, DerefMut};
use std::{ptr, slice};
impl RefPtr<nsCSSShadowArray> {
/// Replaces the current `nsCSSShadowArray` with a new one of len `len`.
pub fn replace_with_new(&mut self, len: u32) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
self.mRawPtr = if len == 0 {
ptr::null_mut()
} else {
Gecko_NewCSSShadowArray(len)
}
}
}
/// Sets the value to other `nsCSSShadowArray`, bumping and decreasing
/// refcounts as needed.
///
/// TODO(emilio): Seems like this could move to `refptr.rs`, and be more
/// generic.
pub fn copy_from(&mut self, other: &Self) {
unsafe {
if !self.mRawPtr.is_null() {
Gecko_ReleaseCSSShadowArrayArbitraryThread(self.mRawPtr);
}
if !other.mRawPtr.is_null() {
Gecko_AddRefCSSShadowArrayArbitraryThread(other.mRawPtr);
}
self.mRawPtr = other.mRawPtr;
}
}
}
impl Deref for RefPtr<nsCSSShadowArray> {
type Target = [nsCSSShadowItem];
fn deref(&self) -> &[nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&[]
} else {
unsafe {
slice::from_raw_parts(
(*self.mRawPtr).mArray.as_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}
}
impl DerefMut for RefPtr<nsCSSShadowArray> {
fn deref_mut(&mut self) -> &mut [nsCSSShadowItem] {
if self.mRawPtr.is_null() {
&mut []
} else {
unsafe {
slice::from_raw_parts_mut(
(*self.mRawPtr).mArray.as_mut_ptr(),
(*self.mRawPtr).mLength as usize,
)
}
}
}
}

View File

@ -0,0 +1,59 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Rust helpers for Gecko's `nsCSSShadowItem`.
use crate::gecko_bindings::structs::nsCSSShadowItem;
use crate::values::computed::effects::{BoxShadow, SimpleShadow};
use app_units::Au;
impl nsCSSShadowItem {
/// Sets this item from the given box shadow.
#[inline]
pub fn set_from_box_shadow(&mut self, shadow: BoxShadow) {
self.set_from_simple_shadow(shadow.base);
self.mSpread = shadow.spread.to_i32_au();
self.mInset = shadow.inset;
}
/// Returns this item as a box shadow.
#[inline]
pub fn to_box_shadow(&self) -> BoxShadow {
BoxShadow {
base: self.extract_simple_shadow(),
spread: Au(self.mSpread).into(),
inset: self.mInset,
}
}
/// Sets this item from the given simple shadow.
#[inline]
pub fn set_from_simple_shadow(&mut self, shadow: SimpleShadow) {
self.mXOffset = shadow.horizontal.to_i32_au();
self.mYOffset = shadow.vertical.to_i32_au();
self.mRadius = shadow.blur.0.to_i32_au();
self.mSpread = 0;
self.mInset = false;
self.mColor = shadow.color.into();
}
/// Gets a simple shadow from this item.
#[inline]
fn extract_simple_shadow(&self) -> SimpleShadow {
SimpleShadow {
color: self.mColor.into(),
horizontal: Au(self.mXOffset).into(),
vertical: Au(self.mYOffset).into(),
blur: Au(self.mRadius).into(),
}
}
/// Returns this item as a simple shadow.
#[inline]
pub fn to_simple_shadow(&self) -> SimpleShadow {
debug_assert_eq!(self.mSpread, 0);
debug_assert_eq!(self.mInset, false);
self.extract_simple_shadow()
}
}

View File

@ -0,0 +1,424 @@
/* 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 https://mozilla.org/MPL/2.0/. */
//! Little helpers for `nsCSSValue`.
use crate::gecko_bindings::bindings;
use crate::gecko_bindings::structs;
use crate::gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
use crate::gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
use crate::gecko_string_cache::Atom;
use crate::values::computed::{Angle, Length, LengthPercentage, Percentage};
use crate::Zero;
use std::marker::PhantomData;
use std::mem;
use std::ops::{Index, IndexMut};
use std::slice;
impl nsCSSValue {
/// Create a CSSValue with null unit, useful to be used as a return value.
#[inline]
pub fn null() -> Self {
unsafe { mem::zeroed() }
}
/// Returns true if this nsCSSValue is none.
#[inline]
pub fn is_none(&self) -> bool {
self.mUnit == nsCSSUnit::eCSSUnit_None
}
/// Returns this nsCSSValue value as an integer, unchecked in release
/// builds.
pub fn integer_unchecked(&self) -> i32 {
debug_assert!(
self.mUnit == nsCSSUnit::eCSSUnit_Integer ||
self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
);
unsafe { *self.mValue.mInt.as_ref() }
}
/// Checks if it is an integer and returns it if so
pub fn integer(&self) -> Option<i32> {
if self.mUnit == nsCSSUnit::eCSSUnit_Integer || self.mUnit == nsCSSUnit::eCSSUnit_Enumerated
{
Some(unsafe { *self.mValue.mInt.as_ref() })
} else {
None
}
}
/// Returns this nsCSSValue value as a floating point value, unchecked in
/// release builds.
pub fn float_unchecked(&self) -> f32 {
debug_assert!(nsCSSUnit::eCSSUnit_Number as u32 <= self.mUnit as u32);
unsafe { *self.mValue.mFloat.as_ref() }
}
/// Returns this nsCSSValue as a nsCSSValue::Array, unchecked in release
/// builds.
pub unsafe fn array_unchecked(&self) -> &nsCSSValue_Array {
debug_assert!(
nsCSSUnit::eCSSUnit_Array as u32 <= self.mUnit as u32 &&
self.mUnit as u32 <= nsCSSUnit::eCSSUnit_Calc_Plus as u32
);
let array = *self.mValue.mArray.as_ref();
debug_assert!(!array.is_null());
&*array
}
/// Sets LengthPercentage value to this nsCSSValue.
pub unsafe fn set_length_percentage(&mut self, lp: LengthPercentage) {
if lp.was_calc {
return bindings::Gecko_CSSValue_SetCalc(self, lp.into());
}
debug_assert!(!lp.has_percentage || lp.unclamped_length() == Length::zero());
if lp.has_percentage {
return self.set_percentage(lp.percentage());
}
self.set_px(lp.unclamped_length().px());
}
/// Sets a px value to this nsCSSValue.
pub unsafe fn set_px(&mut self, px: f32) {
bindings::Gecko_CSSValue_SetPixelLength(self, px)
}
/// Sets a percentage value to this nsCSSValue.
pub unsafe fn set_percentage(&mut self, unit_value: f32) {
bindings::Gecko_CSSValue_SetPercentage(self, unit_value)
}
/// Returns LengthPercentage value.
pub unsafe fn get_length_percentage(&self) -> LengthPercentage {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => {
LengthPercentage::new(Length::new(bindings::Gecko_CSSValue_GetNumber(self)), None)
},
nsCSSUnit::eCSSUnit_Percent => LengthPercentage::new_percent(Percentage(
bindings::Gecko_CSSValue_GetPercentage(self),
)),
nsCSSUnit::eCSSUnit_Calc => bindings::Gecko_CSSValue_GetCalc(self).into(),
_ => panic!("Unexpected unit"),
}
}
/// Returns Length value.
pub unsafe fn get_length(&self) -> Length {
match self.mUnit {
nsCSSUnit::eCSSUnit_Pixel => Length::new(bindings::Gecko_CSSValue_GetNumber(self)),
_ => panic!("Unexpected unit"),
}
}
fn set_valueless_unit(&mut self, unit: nsCSSUnit) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
debug_assert!(
unit as u32 <= nsCSSUnit::eCSSUnit_DummyInherit as u32,
"Not a valueless unit"
);
self.mUnit = unit;
}
/// Set to an auto value
///
/// This method requires the current value to be null.
pub fn set_auto(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Auto);
}
/// Set to a normal value
///
/// This method requires the current value to be null.
pub fn set_normal(&mut self) {
self.set_valueless_unit(nsCSSUnit::eCSSUnit_Normal);
}
fn set_string_internal(&mut self, s: &str, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetString(self, s.as_ptr(), s.len() as u32, unit) }
}
fn set_string_from_atom_internal(&mut self, s: &Atom, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetStringFromAtom(self, s.as_ptr(), unit) }
}
/// Set to a string value
pub fn set_string(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a string value from the given atom
pub fn set_string_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_String)
}
/// Set to a ident value from the given atom
pub fn set_ident_from_atom(&mut self, s: &Atom) {
self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an identifier value
pub fn set_ident(&mut self, s: &str) {
self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident)
}
/// Set to an atom identifier value
pub fn set_atom_ident(&mut self, s: Atom) {
unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
}
fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) {
unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
}
/// Set to an integer value
pub fn set_integer(&mut self, value: i32) {
self.set_int_internal(value, nsCSSUnit::eCSSUnit_Integer)
}
/// Set to an enumerated value
pub fn set_enum<T: Into<i32>>(&mut self, value: T) {
self.set_int_internal(value.into(), nsCSSUnit::eCSSUnit_Enumerated);
}
/// Set to a number value
pub fn set_number(&mut self, number: f32) {
unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
}
/// Set to an array of given length
pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap()
}
/// Generic set from any value that implements the ToNsCssValue trait.
pub fn set_from<T: ToNsCssValue>(&mut self, value: T) {
value.convert(self)
}
/// Returns an `Angle` value from this `nsCSSValue`.
///
/// Panics if the unit is not `eCSSUnit_Degree`.
#[inline]
pub fn get_angle(&self) -> Angle {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Degree);
Angle::from_degrees(self.float_unchecked())
}
/// Sets Angle value to this nsCSSValue.
pub fn set_angle(&mut self, angle: Angle) {
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_Null);
self.mUnit = nsCSSUnit::eCSSUnit_Degree;
unsafe {
*self.mValue.mFloat.as_mut() = angle.degrees();
}
}
/// Set to a pair value
///
/// This is only supported on the main thread.
pub fn set_pair(&mut self, x: &nsCSSValue, y: &nsCSSValue) {
unsafe { bindings::Gecko_CSSValue_SetPair(self, x, y) }
}
/// Set to a list value
///
/// This is only supported on the main thread.
pub fn set_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_List);
let list: &mut structs::nsCSSValueList = &mut unsafe {
self.mValue
.mList
.as_ref() // &*nsCSSValueList_heap
.as_mut()
.expect("List pointer should be non-null")
}
._base;
for (item, new_value) in list.into_iter().zip(values) {
*item = new_value;
}
}
/// Set to a pair list value
///
/// This is only supported on the main thread.
pub fn set_pair_list<I>(&mut self, mut values: I)
where
I: ExactSizeIterator<Item = (nsCSSValue, nsCSSValue)>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe {
bindings::Gecko_CSSValue_SetPairList(self, values.len() as u32);
}
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_PairList);
let mut item_ptr = &mut unsafe {
self.mValue
.mPairList
.as_ref() // &*nsCSSValuePairList_heap
.as_mut()
.expect("List pointer should be non-null")
}
._base as *mut structs::nsCSSValuePairList;
while let Some(item) = unsafe { item_ptr.as_mut() } {
let value = values.next().expect("Values shouldn't have been exhausted");
item.mXValue = value.0;
item.mYValue = value.1;
item_ptr = item.mNext;
}
debug_assert!(values.next().is_none(), "Values should have been exhausted");
}
/// Set a shared list
pub fn set_shared_list<I>(&mut self, values: I)
where
I: ExactSizeIterator<Item = nsCSSValue>,
{
debug_assert!(values.len() > 0, "Empty list is not supported");
unsafe { bindings::Gecko_CSSValue_InitSharedList(self, values.len() as u32) };
debug_assert_eq!(self.mUnit, nsCSSUnit::eCSSUnit_SharedList);
let list = unsafe {
self.mValue
.mSharedList
.as_ref()
.as_mut()
.expect("List pointer should be non-null")
.mHead
.as_mut()
};
debug_assert!(list.is_some(), "New created shared list shouldn't be null");
for (item, new_value) in list.unwrap().into_iter().zip(values) {
*item = new_value;
}
}
}
impl Drop for nsCSSValue {
fn drop(&mut self) {
unsafe { bindings::Gecko_CSSValue_Drop(self) };
}
}
/// Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListIterator<'a> {
current: Option<&'a nsCSSValueList>,
}
impl<'a> Iterator for nsCSSValueListIterator<'a> {
type Item = &'a nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match self.current {
Some(item) => {
self.current = unsafe { item.mNext.as_ref() };
Some(&item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a nsCSSValueList {
type Item = &'a nsCSSValue;
type IntoIter = nsCSSValueListIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListIterator {
current: Some(self),
}
}
}
/// Mutable Iterator of nsCSSValueList.
#[allow(non_camel_case_types)]
pub struct nsCSSValueListMutIterator<'a> {
current: *mut nsCSSValueList,
phantom: PhantomData<&'a mut nsCSSValue>,
}
impl<'a> Iterator for nsCSSValueListMutIterator<'a> {
type Item = &'a mut nsCSSValue;
fn next(&mut self) -> Option<Self::Item> {
match unsafe { self.current.as_mut() } {
Some(item) => {
self.current = item.mNext;
Some(&mut item.mValue)
},
None => None,
}
}
}
impl<'a> IntoIterator for &'a mut nsCSSValueList {
type Item = &'a mut nsCSSValue;
type IntoIter = nsCSSValueListMutIterator<'a>;
fn into_iter(self) -> Self::IntoIter {
nsCSSValueListMutIterator {
current: self as *mut nsCSSValueList,
phantom: PhantomData,
}
}
}
impl nsCSSValue_Array {
/// Return the length of this `nsCSSValue::Array`
#[inline]
pub fn len(&self) -> usize {
self.mCount
}
#[inline]
fn buffer(&self) -> *const nsCSSValue {
self.mArray.as_ptr()
}
/// Get the array as a slice of nsCSSValues.
#[inline]
pub fn as_slice(&self) -> &[nsCSSValue] {
unsafe { slice::from_raw_parts(self.buffer(), self.len()) }
}
/// Get the array as a mutable slice of nsCSSValues.
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [nsCSSValue] {
unsafe { slice::from_raw_parts_mut(self.buffer() as *mut _, self.len()) }
}
}
impl Index<usize> for nsCSSValue_Array {
type Output = nsCSSValue;
#[inline]
fn index(&self, i: usize) -> &nsCSSValue {
&self.as_slice()[i]
}
}
impl IndexMut<usize> for nsCSSValue_Array {
#[inline]
fn index_mut(&mut self, i: usize) -> &mut nsCSSValue {
&mut self.as_mut_slice()[i]
}
}
/// Generic conversion to nsCSSValue
pub trait ToNsCssValue {
/// Convert
fn convert(self, nscssvalue: &mut nsCSSValue);
}
impl<T: ToNsCssValue> From<T> for nsCSSValue {
fn from(value: T) -> nsCSSValue {
let mut result = nsCSSValue::null();
value.convert(&mut result);
result
}
}

View File

@ -289,6 +289,11 @@ impl_threadsafe_refcount!(
bindings::Gecko_AddRefURLExtraDataArbitraryThread,
bindings::Gecko_ReleaseURLExtraDataArbitraryThread
);
impl_threadsafe_refcount!(
structs::nsCSSValueSharedList,
bindings::Gecko_AddRefCSSValueSharedListArbitraryThread,
bindings::Gecko_ReleaseCSSValueSharedListArbitraryThread
);
impl_threadsafe_refcount!(
structs::mozilla::css::URLValue,
bindings::Gecko_AddRefCSSURLValueArbitraryThread,

View File

@ -53,7 +53,6 @@ macro_rules! local_name {
/// This is either a strong reference to a dynamic atom (an nsAtom pointer),
/// or an offset from gGkAtoms to the nsStaticAtom object.
#[derive(Eq, PartialEq)]
#[repr(C)]
pub struct Atom(usize);
/// An atom *without* a strong reference.

View File

@ -190,7 +190,6 @@ pub use servo_atoms::Atom;
pub use style_traits::arc_slice::ArcSlice;
pub use style_traits::owned_slice::OwnedSlice;
pub use style_traits::owned_str::OwnedStr;
/// The CSS properties supported by the style system.
/// Generated from the properties.mako.rs template by build.rs

View File

@ -628,6 +628,10 @@ impl<'a, 'b: 'a> Cascade<'a, 'b> {
#[cfg(feature = "gecko")]
{
if let Some(display) = builder.get_box_if_mutated() {
display.generate_combined_transform();
}
if let Some(bg) = builder.get_background_if_mutated() {
bg.fill_arrays();
}

View File

@ -174,7 +174,6 @@ class Longhand(object):
logical=False, logical_group=None, alias=None, extra_prefixes=None, boxed=False,
flags=None, allowed_in_page_rule=False, allow_quirks=False,
ignored_when_colors_disabled=False,
simple_vector_bindings=False,
vector=False, servo_restyle_damage="repaint"):
self.name = name
if not spec:
@ -211,7 +210,6 @@ class Longhand(object):
self.allow_quirks = allow_quirks
self.ignored_when_colors_disabled = ignored_when_colors_disabled
self.is_vector = vector
self.simple_vector_bindings = simple_vector_bindings
# https://drafts.csswg.org/css-animations/#keyframes
# > The <declaration-list> inside of <keyframe-block> accepts any CSS property

View File

@ -28,6 +28,7 @@ use crate::gecko_bindings::bindings::Gecko_CopyListStyleImageFrom;
use crate::gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
use crate::gecko_bindings::bindings::Gecko_SetCursorArrayLength;
use crate::gecko_bindings::bindings::Gecko_SetCursorImageValue;
use crate::gecko_bindings::bindings::Gecko_NewCSSShadowArray;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone;
@ -55,7 +56,7 @@ use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize;
use crate::values::computed::effects::Filter;
use crate::values::computed::effects::{BoxShadow, Filter, SimpleShadow};
use crate::values::generics::column::ColumnCount;
use crate::values::generics::transform::TransformStyle;
use crate::values::generics::url::UrlOrNone;
@ -302,14 +303,14 @@ impl ${style_struct.gecko_struct_name} {
<%def name="impl_simple_clone(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
From::from(self.gecko.${gecko_ffi_name}.clone())
From::from(self.gecko.${gecko_ffi_name})
}
</%def>
<%def name="impl_simple_copy(ident, gecko_ffi_name, *kwargs)">
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name}.clone();
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
}
#[allow(non_snake_case)]
@ -811,6 +812,281 @@ def set_gecko_property(ffi_name, expr):
}
</%def>
<%
transform_functions = [
("Matrix3D", "matrix3d", ["number"] * 16),
("Matrix", "matrix", ["number"] * 6),
("Translate", "translate", ["lp", "lp"]),
("Translate3D", "translate3d", ["lp", "lp", "length"]),
("TranslateX", "translatex", ["lp"]),
("TranslateY", "translatey", ["lp"]),
("TranslateZ", "translatez", ["length"]),
("Scale3D", "scale3d", ["number"] * 3),
("Scale", "scale", ["number", "number"]),
("ScaleX", "scalex", ["number"]),
("ScaleY", "scaley", ["number"]),
("ScaleZ", "scalez", ["number"]),
("Rotate", "rotate", ["angle"]),
("Rotate3D", "rotate3d", ["number"] * 3 + ["angle"]),
("RotateX", "rotatex", ["angle"]),
("RotateY", "rotatey", ["angle"]),
("RotateZ", "rotatez", ["angle"]),
("Skew", "skew", ["angle", "angle"]),
("SkewX", "skewx", ["angle"]),
("SkewY", "skewy", ["angle"]),
("Perspective", "perspective", ["length"]),
("InterpolateMatrix", "interpolatematrix", ["list"] * 2 + ["percentage"]),
("AccumulateMatrix", "accumulatematrix", ["list"] * 2 + ["integer_to_percentage"])
]
%>
<%def name="transform_function_arm(name, keyword, items)">
<%
pattern = None
if keyword == "matrix3d":
# m11: number1, m12: number2, ..
single_patterns = ["m%s: %s" % (str(a / 4 + 1) + str(a % 4 + 1), b + str(a + 1)) for (a, b)
in enumerate(items)]
pattern = "(Matrix3D { %s })" % ", ".join(single_patterns)
elif keyword == "matrix":
# a: number1, b: number2, ..
single_patterns = ["%s: %s" % (chr(ord('a') + a), b + str(a + 1)) for (a, b)
in enumerate(items)]
pattern = "(Matrix { %s })" % ", ".join(single_patterns)
elif keyword == "interpolatematrix":
pattern = " { from_list: ref list1, to_list: ref list2, progress: percentage3 }"
elif keyword == "accumulatematrix":
pattern = " { from_list: ref list1, to_list: ref list2, count: integer_to_percentage3 }"
else:
# Generate contents of pattern from items
pattern = "(%s)" % ", ".join([b + str(a+1) for (a,b) in enumerate(items)])
# First %s substituted with the call to GetArrayItem, the second
# %s substituted with the corresponding variable
css_value_setters = {
"length" : "bindings::Gecko_CSSValue_SetPixelLength(%s, %s.px())",
"percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s.0)",
# Note: This is an integer type, but we use it as a percentage value in Gecko, so
# need to cast it to f32.
"integer_to_percentage" : "bindings::Gecko_CSSValue_SetPercentage(%s, %s as f32)",
"lp" : "%s.set_length_percentage(%s)",
"angle" : "%s.set_angle(%s)",
"number" : "bindings::Gecko_CSSValue_SetNumber(%s, %s)",
# Note: We use nsCSSValueSharedList here, instead of nsCSSValueList_heap
# because this function is not called on the main thread and
# nsCSSValueList_heap is not thread safe.
"list" : "%s.set_shared_list(%s.0.iter().map(&convert_to_ns_css_value));",
}
%>
crate::values::generics::transform::TransformOperation::${name}${pattern} => {
let len = ${len(items) + 1};
bindings::Gecko_CSSValue_SetFunction(gecko_value, len);
bindings::Gecko_CSSValue_SetKeyword(
bindings::Gecko_CSSValue_GetArrayItem(gecko_value, 0),
structs::nsCSSKeyword::eCSSKeyword_${keyword}
);
% for index, item in enumerate(items):
% if item == "list":
debug_assert!(!${item}${index + 1}.0.is_empty());
% endif
${css_value_setters[item] % (
"(&mut *bindings::Gecko_CSSValue_GetArrayItem(gecko_value, %d))" % (index + 1),
item + str(index + 1)
)};
% endfor
}
</%def>
<%def name="computed_operation_arm(name, keyword, items)">
<%
# %s is substituted with the call to GetArrayItem.
css_value_getters = {
"length" : "Length::new(bindings::Gecko_CSSValue_GetNumber(%s))",
"lp" : "%s.get_length_percentage()",
"angle" : "%s.get_angle()",
"number" : "bindings::Gecko_CSSValue_GetNumber(%s)",
"percentage" : "Percentage(bindings::Gecko_CSSValue_GetPercentage(%s))",
"integer_to_percentage" : "bindings::Gecko_CSSValue_GetPercentage(%s) as i32",
"list" : "Transform(convert_shared_list_to_operations(%s))",
}
pre_symbols = "("
post_symbols = ")"
if keyword == "interpolatematrix" or keyword == "accumulatematrix":
# We generate this like: "TransformOperation::InterpolateMatrix {", so the space is
# between "InterpolateMatrix"/"AccumulateMatrix" and '{'
pre_symbols = " {"
post_symbols = "}"
elif keyword == "matrix3d":
pre_symbols = "(Matrix3D {"
post_symbols = "})"
elif keyword == "matrix":
pre_symbols = "(Matrix {"
post_symbols = "})"
field_names = None
if keyword == "interpolatematrix":
field_names = ["from_list", "to_list", "progress"]
elif keyword == "accumulatematrix":
field_names = ["from_list", "to_list", "count"]
%>
structs::nsCSSKeyword::eCSSKeyword_${keyword} => {
crate::values::generics::transform::TransformOperation::${name}${pre_symbols}
% for index, item in enumerate(items):
% if keyword == "matrix3d":
m${index / 4 + 1}${index % 4 + 1}:
% elif keyword == "matrix":
${chr(ord('a') + index)}:
% elif keyword == "interpolatematrix" or keyword == "accumulatematrix":
${field_names[index]}:
% endif
<%
getter = css_value_getters[item] % (
"(&*bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, %d))" % (index + 1)
)
%>
${getter},
% endfor
${post_symbols}
},
</%def>
#[allow(unused_parens)]
fn set_single_transform_function(
servo_value: &values::computed::TransformOperation,
gecko_value: &mut structs::nsCSSValue /* output */
) {
use crate::values::computed::TransformOperation;
use crate::values::generics::transform::{Matrix, Matrix3D};
let convert_to_ns_css_value = |item: &TransformOperation| -> structs::nsCSSValue {
let mut value = structs::nsCSSValue::null();
set_single_transform_function(item, &mut value);
value
};
unsafe {
match *servo_value {
% for servo, gecko, format in transform_functions:
${transform_function_arm(servo, gecko, format)}
% endfor
}
}
}
pub fn convert_transform(
input: &[values::computed::TransformOperation],
output: &mut structs::root::RefPtr<structs::root::nsCSSValueSharedList>
) {
use crate::gecko_bindings::sugar::refptr::RefPtr;
unsafe { output.clear() };
let list = unsafe {
RefPtr::from_addrefed(bindings::Gecko_NewCSSValueSharedList(input.len() as u32))
};
let value_list = unsafe { list.mHead.as_mut() };
if let Some(value_list) = value_list {
for (gecko, servo) in value_list.into_iter().zip(input.into_iter()) {
set_single_transform_function(servo, gecko);
}
}
output.set_move(list);
}
#[allow(unused_parens)]
fn clone_single_transform_function(
gecko_value: &structs::nsCSSValue
) -> values::computed::TransformOperation {
use crate::values::computed::{Length, Percentage, TransformOperation};
use crate::values::generics::transform::{Matrix, Matrix3D};
use crate::values::generics::transform::Transform;
let convert_shared_list_to_operations = |value: &structs::nsCSSValue|
-> Vec<TransformOperation> {
debug_assert_eq!(value.mUnit, structs::nsCSSUnit::eCSSUnit_SharedList);
let value_list = unsafe {
value.mValue.mSharedList.as_ref()
.as_mut().expect("List pointer should be non-null").mHead.as_ref()
};
debug_assert!(value_list.is_some(), "An empty shared list is not allowed");
value_list.unwrap().into_iter()
.map(|item| clone_single_transform_function(item))
.collect()
};
let transform_function = unsafe {
bindings::Gecko_CSSValue_GetKeyword(bindings::Gecko_CSSValue_GetArrayItemConst(gecko_value, 0))
};
unsafe {
match transform_function {
% for servo, gecko, format in transform_functions:
${computed_operation_arm(servo, gecko, format)}
% endfor
_ => panic!("unacceptable transform function"),
}
}
}
pub fn clone_transform_from_list(
list: Option< &structs::root::nsCSSValueList>
) -> values::computed::Transform {
use crate::values::generics::transform::Transform;
let result = match list {
Some(list) => {
list.into_iter()
.filter_map(|value| {
// Handle none transform.
if value.is_none() {
None
} else {
Some(clone_single_transform_function(value))
}
})
.collect::<Vec<_>>()
},
_ => vec![],
};
Transform(result)
}
<%def name="impl_transform(ident, gecko_ffi_name)">
#[allow(non_snake_case)]
pub fn set_${ident}(&mut self, other: values::computed::Transform) {
use crate::gecko_properties::convert_transform;
if other.0.is_empty() {
unsafe {
self.gecko.${gecko_ffi_name}.clear();
}
return;
};
convert_transform(&other.0, &mut self.gecko.${gecko_ffi_name});
}
#[allow(non_snake_case)]
pub fn copy_${ident}_from(&mut self, other: &Self) {
unsafe { self.gecko.${gecko_ffi_name}.set(&other.gecko.${gecko_ffi_name}); }
}
#[allow(non_snake_case)]
pub fn reset_${ident}(&mut self, other: &Self) {
self.copy_${ident}_from(other)
}
#[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> values::computed::Transform {
use crate::gecko_properties::clone_transform_from_list;
use crate::values::generics::transform::Transform;
if self.gecko.${gecko_ffi_name}.mRawPtr.is_null() {
return Transform(vec!());
}
let list = unsafe { (*self.gecko.${gecko_ffi_name}.to_safe().get()).mHead.as_ref() };
clone_transform_from_list(list)
}
</%def>
<%def name="impl_logical(name, **kwargs)">
${helpers.logical_setter(name)}
</%def>
@ -916,6 +1192,7 @@ impl Clone for ${style_struct.gecko_struct_name} {
"SVGOpacity": impl_svg_opacity,
"SVGPaint": impl_svg_paint,
"SVGWidth": impl_svg_length,
"Transform": impl_transform,
"url::UrlOrNone": impl_css_url,
}
@ -2235,11 +2512,17 @@ fn static_assert() {
animation-iteration-count animation-timing-function
clear transition-duration transition-delay
transition-timing-function transition-property
transform-style scroll-snap-points-x
scroll-snap-points-y scroll-snap-coordinate
-moz-binding offset-path shape-outside
-webkit-line-clamp""" %>
transform-style
rotate scroll-snap-points-x scroll-snap-points-y
scroll-snap-coordinate -moz-binding will-change
offset-path shape-outside
translate scale -webkit-line-clamp""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline]
pub fn generate_combined_transform(&mut self) {
unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut *self.gecko) };
}
#[inline]
pub fn set_display(&mut self, v: longhands::display::computed_value::T) {
self.gecko.mDisplay = v;
@ -2543,6 +2826,70 @@ fn static_assert() {
${impl_animation_timing_function()}
${impl_individual_transform('rotate', 'Rotate', 'mSpecifiedRotate')}
${impl_individual_transform('translate', 'Translate', 'mSpecifiedTranslate')}
${impl_individual_transform('scale', 'Scale', 'mSpecifiedScale')}
pub fn set_will_change(&mut self, v: longhands::will_change::computed_value::T) {
use crate::gecko_bindings::bindings::{Gecko_AppendWillChange, Gecko_ClearWillChange};
use crate::values::specified::box_::{WillChangeBits, WillChange};
match v {
WillChange::AnimateableFeatures { features, bits } => {
unsafe {
Gecko_ClearWillChange(&mut *self.gecko, features.len());
}
for feature in features.iter() {
unsafe {
Gecko_AppendWillChange(&mut *self.gecko, feature.0.as_ptr())
}
}
self.gecko.mWillChangeBitField = bits;
},
WillChange::Auto => {
unsafe {
Gecko_ClearWillChange(&mut *self.gecko, 0);
}
self.gecko.mWillChangeBitField = WillChangeBits::empty();
},
};
}
pub fn copy_will_change_from(&mut self, other: &Self) {
use crate::gecko_bindings::bindings::Gecko_CopyWillChangeFrom;
self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField;
unsafe {
Gecko_CopyWillChangeFrom(&mut *self.gecko, &*other.gecko);
}
}
pub fn reset_will_change(&mut self, other: &Self) {
self.copy_will_change_from(other)
}
pub fn clone_will_change(&self) -> longhands::will_change::computed_value::T {
use crate::values::CustomIdent;
use crate::values::specified::box_::WillChange;
if self.gecko.mWillChange.len() == 0 {
return WillChange::Auto
}
let custom_idents: Vec<CustomIdent> = self.gecko.mWillChange.iter().map(|gecko_atom| {
unsafe {
CustomIdent(Atom::from_raw(gecko_atom.mRawPtr))
}
}).collect();
WillChange::AnimateableFeatures {
features: custom_idents.into_boxed_slice(),
bits: self.gecko.mWillChangeBitField,
}
}
<% impl_shape_source("shape_outside", "mShapeOutside") %>
pub fn set_offset_path(&mut self, v: longhands::offset_path::computed_value::T) {
@ -2955,7 +3302,7 @@ fn static_assert() {
</%self:impl_trait>
<%self:impl_trait style_struct_name="List"
skip_longhands="list-style-image list-style-type -moz-image-region">
skip_longhands="list-style-image list-style-type quotes -moz-image-region">
pub fn set_list_style_image(&mut self, image: longhands::list_style_image::computed_value::T) {
match image {
@ -3031,6 +3378,28 @@ fn static_assert() {
}
}
pub fn set_quotes(&mut self, other: longhands::quotes::computed_value::T) {
self.gecko.mQuotes.set_arc(other.0.clone());
}
pub fn copy_quotes_from(&mut self, other: &Self) {
self.set_quotes(other.clone_quotes());
}
pub fn reset_quotes(&mut self, other: &Self) {
self.copy_quotes_from(other)
}
pub fn clone_quotes(&self) -> longhands::quotes::computed_value::T {
use gecko_bindings::sugar::ownership::HasArcFFI;
use values::computed::QuotePair;
let quote_pairs = unsafe { &*self.gecko.mQuotes.mRawPtr };
longhands::quotes::computed_value::T(
Box::<[QuotePair]>::as_arc(&quote_pairs).clone_arc()
)
}
#[allow(non_snake_case)]
pub fn set__moz_image_region(&mut self, v: longhands::_moz_image_region::computed_value::T) {
use crate::values::Either;
@ -3108,7 +3477,31 @@ fn static_assert() {
</%self:impl_trait>
<%self:impl_trait style_struct_name="Effects"
skip_longhands="clip filter">
skip_longhands="box-shadow clip filter">
pub fn set_box_shadow<I>(&mut self, v: I)
where I: IntoIterator<Item = BoxShadow>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
self.gecko.mBoxShadow.replace_with_new(v.len() as u32);
for (servo, gecko_shadow) in v.zip(self.gecko.mBoxShadow.iter_mut()) {
gecko_shadow.set_from_box_shadow(servo);
}
}
pub fn copy_box_shadow_from(&mut self, other: &Self) {
self.gecko.mBoxShadow.copy_from(&other.gecko.mBoxShadow);
}
pub fn reset_box_shadow(&mut self, other: &Self) {
self.copy_box_shadow_from(other)
}
pub fn clone_box_shadow(&self) -> longhands::box_shadow::computed_value::T {
let buf = self.gecko.mBoxShadow.iter().map(|v| v.to_box_shadow()).collect();
longhands::box_shadow::computed_value::List(buf)
}
pub fn set_clip(&mut self, v: longhands::clip::computed_value::T) {
use crate::gecko_bindings::structs::NS_STYLE_CLIP_AUTO;
use crate::gecko_bindings::structs::NS_STYLE_CLIP_RECT;
@ -3232,6 +3625,7 @@ fn static_assert() {
I::IntoIter: ExactSizeIterator,
{
use crate::values::generics::effects::Filter::*;
use crate::gecko_bindings::structs::nsCSSShadowArray;
use crate::gecko_bindings::structs::nsStyleFilter;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_BLUR;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_BRIGHTNESS;
@ -3272,10 +3666,19 @@ fn static_assert() {
DropShadow(shadow) => {
gecko_filter.mType = NS_STYLE_FILTER_DROP_SHADOW;
unsafe {
let ref mut union = gecko_filter.__bindgen_anon_1;
ptr::write(union.mDropShadow.as_mut(), shadow);
fn init_shadow(filter: &mut nsStyleFilter) -> &mut nsCSSShadowArray {
unsafe {
let ref mut union = filter.__bindgen_anon_1;
let shadow_array: &mut *mut nsCSSShadowArray = union.mDropShadow.as_mut();
*shadow_array = Gecko_NewCSSShadowArray(1);
&mut **shadow_array
}
}
let gecko_shadow = init_shadow(gecko_filter);
gecko_shadow.mArray[0].set_from_simple_shadow(shadow);
},
Url(ref url) => {
unsafe {
@ -3311,41 +3714,42 @@ fn static_assert() {
use crate::gecko_bindings::structs::NS_STYLE_FILTER_DROP_SHADOW;
use crate::gecko_bindings::structs::NS_STYLE_FILTER_URL;
longhands::filter::computed_value::List(self.gecko.mFilters.iter().map(|filter| {
let mut filters = Vec::new();
for filter in self.gecko.mFilters.iter(){
match filter.mType {
% for func in FILTER_FUNCTIONS:
NS_STYLE_FILTER_${func.upper()} => {
Filter::${func}(
filters.push(Filter::${func}(
GeckoStyleCoordConvertible::from_gecko_style_coord(
&filter.mFilterParameter
).unwrap()
)
&filter.mFilterParameter).unwrap()));
},
% endfor
NS_STYLE_FILTER_BLUR => {
Filter::Blur(NonNegativeLength::from_gecko_style_coord(
&filter.mFilterParameter
).unwrap())
filters.push(Filter::Blur(NonNegativeLength::from_gecko_style_coord(
&filter.mFilterParameter).unwrap()));
},
NS_STYLE_FILTER_HUE_ROTATE => {
Filter::HueRotate(GeckoStyleCoordConvertible::from_gecko_style_coord(
&filter.mFilterParameter,
).unwrap())
filters.push(Filter::HueRotate(
GeckoStyleCoordConvertible::from_gecko_style_coord(
&filter.mFilterParameter).unwrap()));
},
NS_STYLE_FILTER_DROP_SHADOW => {
Filter::DropShadow(unsafe {
(*filter.__bindgen_anon_1.mDropShadow.as_ref()).clone()
})
filters.push(unsafe {
Filter::DropShadow(
(**filter.__bindgen_anon_1.mDropShadow.as_ref()).mArray[0].to_simple_shadow(),
)
});
},
NS_STYLE_FILTER_URL => {
Filter::Url(unsafe {
filters.push(Filter::Url(unsafe {
let url = RefPtr::new(*filter.__bindgen_anon_1.mURL.as_ref());
ComputedUrl::from_url_value(url)
})
}));
}
_ => unreachable!("Unknown filter function?"),
_ => {},
}
}).collect())
}
longhands::filter::computed_value::List(filters)
}
</%self:impl_trait>
@ -3380,7 +3784,7 @@ fn static_assert() {
<%self:impl_trait style_struct_name="InheritedText"
skip_longhands="text-align text-emphasis-style
skip_longhands="text-align text-emphasis-style text-shadow
-webkit-text-stroke-width text-emphasis-position">
<% text_align_keyword = Keyword("text-align",
@ -3388,6 +3792,30 @@ fn static_assert() {
gecko_strip_moz_prefix=False) %>
${impl_keyword('text_align', 'mTextAlign', text_align_keyword)}
pub fn set_text_shadow<I>(&mut self, v: I)
where I: IntoIterator<Item = SimpleShadow>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
self.gecko.mTextShadow.replace_with_new(v.len() as u32);
for (servo, gecko_shadow) in v.zip(self.gecko.mTextShadow.iter_mut()) {
gecko_shadow.set_from_simple_shadow(servo);
}
}
pub fn copy_text_shadow_from(&mut self, other: &Self) {
self.gecko.mTextShadow.copy_from(&other.gecko.mTextShadow);
}
pub fn reset_text_shadow(&mut self, other: &Self) {
self.copy_text_shadow_from(other)
}
pub fn clone_text_shadow(&self) -> longhands::text_shadow::computed_value::T {
let buf = self.gecko.mTextShadow.iter().map(|v| v.to_simple_shadow()).collect();
longhands::text_shadow::computed_value::List(buf)
}
fn clear_text_emphasis_style_if_string(&mut self) {
if self.gecko.mTextEmphasisStyle == structs::NS_STYLE_TEXT_EMPHASIS_STYLE_STRING as u8 {
self.gecko.mTextEmphasisStyleString.truncate();
@ -3691,7 +4119,7 @@ clip-path
</%self:impl_trait>
<%self:impl_trait style_struct_name="InheritedSVG"
skip_longhands="paint-order stroke-dasharray">
skip_longhands="paint-order stroke-dasharray -moz-context-properties">
pub fn set_paint_order(&mut self, v: longhands::paint_order::computed_value::T) {
self.gecko.mPaintOrder = v.0;
}
@ -3751,6 +4179,62 @@ clip-path
}
SVGStrokeDashArray::Values(self.gecko.mStrokeDasharray.iter().cloned().collect())
}
#[allow(non_snake_case)]
pub fn _moz_context_properties_count(&self) -> usize {
self.gecko.mContextProps.len()
}
#[allow(non_snake_case)]
pub fn _moz_context_properties_at(
&self,
index: usize,
) -> longhands::_moz_context_properties::computed_value::single_value::T {
longhands::_moz_context_properties::computed_value::single_value::T(
CustomIdent(unsafe {
Atom::from_raw(self.gecko.mContextProps[index].mRawPtr)
})
)
}
#[allow(non_snake_case)]
pub fn set__moz_context_properties<I>(&mut self, v: I)
where
I: IntoIterator<Item = longhands::_moz_context_properties::computed_value::single_value::T>,
I::IntoIter: ExactSizeIterator
{
let v = v.into_iter();
unsafe {
bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut *self.gecko, v.len() as u32);
}
let s = &mut *self.gecko;
s.mContextPropsBits = 0;
for (gecko, servo) in s.mContextProps.iter_mut().zip(v) {
if (servo.0).0 == atom!("fill") {
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8;
} else if (servo.0).0 == atom!("stroke") {
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8;
} else if (servo.0).0 == atom!("fill-opacity") {
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY as u8;
} else if (servo.0).0 == atom!("stroke-opacity") {
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY as u8;
}
gecko.mRawPtr = (servo.0).0.into_addrefed();
}
}
#[allow(non_snake_case)]
pub fn copy__moz_context_properties_from(&mut self, other: &Self) {
unsafe {
bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut *self.gecko, &*other.gecko);
}
}
#[allow(non_snake_case)]
pub fn reset__moz_context_properties(&mut self, other: &Self) {
self.copy__moz_context_properties_from(other)
}
</%self:impl_trait>
<%self:impl_trait style_struct_name="Color">

View File

@ -80,26 +80,12 @@
We assume that the default/initial value is an empty vector for these.
`initial_value` need not be defined for these.
</%doc>
// The setup here is roughly:
//
// * UnderlyingList is the list that is stored in the computed value. This may
// be a shared ArcSlice if the property is inherited.
// * UnderlyingOwnedList is the list that is used for animation.
// * Specified values always use OwnedSlice, since it's more compact.
// * computed_value::List is just a convenient alias that you can use for the
// computed value list, since this is in the computed_value module.
//
// If simple_vector_bindings is true, then we don't use the complex iterator
// machinery and set_foo_from, and just compute the value like any other
// longhand.
<%def name="vector_longhand(name, animation_value_type=None,
vector_animation_type=None, allow_empty=False,
simple_vector_bindings=False,
separator='Comma',
**kwargs)">
<%call expr="longhand(name, animation_value_type=animation_value_type, vector=True,
simple_vector_bindings=simple_vector_bindings, **kwargs)">
**kwargs)">
#[allow(unused_imports)]
use smallvec::SmallVec;
@ -125,43 +111,16 @@
/// The definition of the computed value for ${name}.
pub mod computed_value {
#[allow(unused_imports)]
use crate::values::animated::ToAnimatedValue;
#[allow(unused_imports)]
use crate::values::resolved::ToResolvedValue;
pub use super::single_value::computed_value as single_value;
pub use self::single_value::T as SingleComputedValue;
% if not allow_empty or allow_empty == "NotInitial":
use smallvec::SmallVec;
% if allow_empty and allow_empty != "NotInitial":
use std::vec::IntoIter;
% else:
use smallvec::{IntoIter, SmallVec};
% endif
use crate::values::computed::ComputedVecIter;
<% is_shared_list = allow_empty and allow_empty != "NotInitial" and data.longhands_by_name[name].style_struct.inherited %>
// FIXME(emilio): Add an OwnedNonEmptySlice type, and figure out
// something for transition-name, which is the only remaining user
// of NotInitial.
pub type UnderlyingList<T> =
% if allow_empty and allow_empty != "NotInitial":
% if data.longhands_by_name[name].style_struct.inherited:
crate::ArcSlice<T>;
% else:
crate::OwnedSlice<T>;
% endif
% else:
SmallVec<[T; 1]>;
% endif
pub type UnderlyingOwnedList<T> =
% if allow_empty and allow_empty != "NotInitial":
crate::OwnedSlice<T>;
% else:
SmallVec<[T; 1]>;
% endif
/// The generic type defining the animated and resolved values for
/// this property.
/// The generic type defining the value for this property.
///
/// Making this type generic allows the compiler to figure out the
/// animated value for us, instead of having to implement it
@ -178,115 +137,34 @@
ToResolvedValue,
ToCss,
)]
pub struct OwnedList<T>(
pub struct List<T>(
% if not allow_empty:
#[css(iterable)]
% else:
#[css(if_empty = "none", iterable)]
% endif
pub UnderlyingOwnedList<T>,
);
/// The computed value for this property.
% if not is_shared_list:
pub type ComputedList = OwnedList<single_value::T>;
pub use self::OwnedList as List;
% else:
pub use self::ComputedList as List;
% if separator == "Comma":
#[css(comma)]
% endif
#[derive(
Clone,
Debug,
MallocSizeOf,
PartialEq,
ToCss,
)]
pub struct ComputedList(
% if not allow_empty:
#[css(iterable)]
% if allow_empty and allow_empty != "NotInitial":
pub Vec<T>,
% else:
#[css(if_empty = "none", iterable)]
pub SmallVec<[T; 1]>,
% endif
% if is_shared_list:
#[ignore_malloc_size_of = "Arc"]
% endif
pub UnderlyingList<single_value::T>,
);
type ResolvedList = OwnedList<<single_value::T as ToResolvedValue>::ResolvedValue>;
impl ToResolvedValue for ComputedList {
type ResolvedValue = ResolvedList;
fn to_resolved_value(self, context: &crate::values::resolved::Context) -> Self::ResolvedValue {
OwnedList(
self.0
.iter()
.cloned()
.map(|v| v.to_resolved_value(context))
.collect()
)
}
fn from_resolved_value(resolved: Self::ResolvedValue) -> Self {
% if not is_shared_list:
use std::iter::FromIterator;
% endif
let iter =
resolved.0.into_iter().map(ToResolvedValue::from_resolved_value);
ComputedList(UnderlyingList::from_iter(iter))
}
}
% endif
% if simple_vector_bindings:
impl From<ComputedList> for UnderlyingList<single_value::T> {
#[inline]
fn from(l: ComputedList) -> Self {
l.0
}
}
impl From<UnderlyingList<single_value::T>> for ComputedList {
#[inline]
fn from(l: UnderlyingList<single_value::T>) -> Self {
List(l)
}
}
% endif
/// The computed value, effectively a list of single values.
% if vector_animation_type:
% if not animation_value_type:
Sorry, this is stupid but needed for now.
% endif
use crate::properties::animated_properties::ListAnimation;
use crate::values::animated::{Animate, ToAnimatedZero, Procedure};
use crate::values::animated::{Animate, ToAnimatedValue, ToAnimatedZero, Procedure};
use crate::values::distance::{SquaredDistance, ComputeSquaredDistance};
// FIXME(emilio): For some reason rust thinks that this alias is
// unused, even though it's clearly used below?
#[allow(unused)]
type AnimatedList = OwnedList<<single_value::T as ToAnimatedValue>::AnimatedValue>;
% if is_shared_list:
impl ToAnimatedValue for ComputedList {
type AnimatedValue = AnimatedList;
fn to_animated_value(self) -> Self::AnimatedValue {
OwnedList(
self.0.iter().map(|v| v.clone().to_animated_value()).collect()
)
}
fn from_animated_value(animated: Self::AnimatedValue) -> Self {
let iter =
animated.0.into_iter().map(ToAnimatedValue::from_animated_value);
ComputedList(UnderlyingList::from_iter(iter))
}
}
% endif
type AnimatedList = <List<single_value::T> as ToAnimatedValue>::AnimatedValue;
impl ToAnimatedZero for AnimatedList {
fn to_animated_zero(&self) -> Result<Self, ()> { Err(()) }
@ -298,7 +176,7 @@
other: &Self,
procedure: Procedure,
) -> Result<Self, ()> {
Ok(OwnedList(
Ok(List(
self.0.animate_${vector_animation_type}(&other.0, procedure)?
))
}
@ -313,10 +191,21 @@
}
% endif
/// The computed value, effectively a list of single values.
pub use self::ComputedList as T;
pub type T = List<single_value::T>;
pub type Iter<'a, 'cx, 'cx_a> = ComputedVecIter<'a, 'cx, 'cx_a, super::single_value::SpecifiedValue>;
impl IntoIterator for T {
type Item = single_value::T;
% if allow_empty and allow_empty != "NotInitial":
type IntoIter = IntoIter<single_value::T>;
% else:
type IntoIter = IntoIter<[single_value::T; 1]>;
% endif
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
}
/// The specified value of ${name}.
@ -330,12 +219,12 @@
% else:
#[css(if_empty = "none", iterable)]
% endif
pub crate::OwnedSlice<single_value::SpecifiedValue>,
pub Vec<single_value::SpecifiedValue>,
);
pub fn get_initial_value() -> computed_value::T {
% if allow_empty and allow_empty != "NotInitial":
computed_value::List(Default::default())
computed_value::List(vec![])
% else:
let mut v = SmallVec::new();
v.push(single_value::get_initial_value());
@ -350,47 +239,40 @@
use style_traits::Separator;
% if allow_empty:
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Default::default()))
}
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
return Ok(SpecifiedValue(Vec::new()))
}
% endif
let v = style_traits::${separator}::parse(input, |parser| {
style_traits::${separator}::parse(input, |parser| {
single_value::parse(context, parser)
})?;
Ok(SpecifiedValue(v.into()))
}).map(SpecifiedValue)
}
pub use self::single_value::SpecifiedValue as SingleSpecifiedValue;
% if not simple_vector_bindings:
impl SpecifiedValue {
fn compute_iter<'a, 'cx, 'cx_a>(
pub fn compute_iter<'a, 'cx, 'cx_a>(
&'a self,
context: &'cx Context<'cx_a>,
) -> computed_value::Iter<'a, 'cx, 'cx_a> {
computed_value::Iter::new(context, &self.0)
}
}
% endif
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
% if not is_shared_list:
use std::iter::FromIterator;
% endif
computed_value::List(computed_value::UnderlyingList::from_iter(
self.0.iter().map(|i| i.to_computed_value(context))
))
computed_value::List(self.compute_iter(context).collect())
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
let iter = computed.0.iter().map(ToComputedValue::from_computed_value);
SpecifiedValue(iter.collect())
SpecifiedValue(computed.0.iter()
.map(ToComputedValue::from_computed_value)
.collect())
}
}
</%call>
@ -493,7 +375,7 @@
.set_writing_mode_dependency(context.builder.writing_mode);
% endif
% if property.is_vector and not property.simple_vector_bindings:
% if property.is_vector:
// In the case of a vector property we want to pass down an
// iterator so that this can be computed without allocation.
//

View File

@ -773,7 +773,6 @@ macro_rules! animated_list_impl {
}
}
animated_list_impl!(<T> for crate::OwnedSlice<T>);
animated_list_impl!(<T> for SmallVec<[T; 1]>);
animated_list_impl!(<T> for Vec<T>);

View File

@ -352,6 +352,7 @@ ${helpers.predefined_type(
"generics::transform::Transform::none()",
extra_prefixes=transform_extra_prefixes,
animation_value_type="ComputedValue",
gecko_ffi_name="mSpecifiedTransform",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB \
GETCS_NEEDS_LAYOUT_FLUSH CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.csswg.org/css-transforms/#propdef-transform",

View File

@ -23,7 +23,6 @@ ${helpers.predefined_type(
"BoxShadow",
None,
vector=True,
simple_vector_bindings=True,
animation_value_type="AnimatedBoxShadowList",
vector_animation_type="with_zero",
extra_prefixes="webkit",

View File

@ -194,8 +194,11 @@ ${helpers.predefined_type(
${helpers.predefined_type(
"-moz-context-properties",
"MozContextProperties",
"computed::MozContextProperties::default()",
products="gecko",
initial_value=None,
vector=True,
need_index=True,
animation_value_type="none",
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)",
allow_empty=True,
)}

View File

@ -218,7 +218,6 @@ ${helpers.predefined_type(
vector_animation_type="with_zero",
animation_value_type="AnimatedTextShadowList",
ignored_when_colors_disabled=True,
simple_vector_bindings=True,
flags="APPLIES_TO_FIRST_LETTER APPLIES_TO_FIRST_LINE APPLIES_TO_PLACEHOLDER",
spec="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property",
)}

View File

@ -81,6 +81,7 @@ ${helpers.predefined_type(
"Transform",
"generics::transform::Transform::none()",
products="gecko",
gecko_ffi_name="mSpecifiedWindowTransform",
flags="GETCS_NEEDS_LAYOUT_FLUSH",
animation_value_type="ComputedValue",
spec="None (Nonstandard internal property)",

View File

@ -3444,7 +3444,7 @@ impl<'a> StyleBuilder<'a> {
}
% endif
% if not property.is_vector or property.simple_vector_bindings:
% if not property.is_vector:
/// Set the `${property.ident}` to the computed value `value`.
#[allow(non_snake_case)]
pub fn set_${property.ident}(

View File

@ -40,11 +40,11 @@
let mut background_color = None;
% for name in "image position_x position_y repeat size attachment origin clip".split():
// Vec grows from 0 to 4 by default on first push(). So allocate with
// capacity 1, so in the common case of only one item we don't way
// overallocate, then shrink. Note that we always push at least one
// item if parsing succeeds.
let mut background_${name} = Vec::with_capacity(1);
// Vec grows from 0 to 4 by default on first push(). So allocate
// with capacity 1, so in the common case of only one item we don't
// way overallocate. Note that we always push at least one item if
// parsing succeeds.
let mut background_${name} = background_${name}::SpecifiedValue(Vec::with_capacity(1));
% endfor
input.parse_comma_separated(|input| {
// background-color can only be in the last element, so if it
@ -99,17 +99,17 @@
any = any || background_color.is_some();
if any {
if let Some(position) = position {
background_position_x.push(position.horizontal);
background_position_y.push(position.vertical);
background_position_x.0.push(position.horizontal);
background_position_y.0.push(position.vertical);
} else {
background_position_x.push(PositionComponent::zero());
background_position_y.push(PositionComponent::zero());
background_position_x.0.push(PositionComponent::zero());
background_position_y.0.push(PositionComponent::zero());
}
% for name in "image repeat size attachment origin clip".split():
if let Some(bg_${name}) = ${name} {
background_${name}.push(bg_${name});
background_${name}.0.push(bg_${name});
} else {
background_${name}.push(background_${name}::single_value
background_${name}.0.push(background_${name}::single_value
::get_initial_specified_value());
}
% endfor
@ -121,9 +121,14 @@
Ok(expanded! {
background_color: background_color.unwrap_or(Color::transparent()),
% for name in "image position_x position_y repeat size attachment origin clip".split():
background_${name}: background_${name}::SpecifiedValue(background_${name}.into()),
% endfor
background_image: background_image,
background_position_x: background_position_x,
background_position_y: background_position_y,
background_repeat: background_repeat,
background_attachment: background_attachment,
background_size: background_size,
background_origin: background_origin,
background_clip: background_clip,
})
}
@ -204,16 +209,16 @@
) -> Result<Longhands, ParseError<'i>> {
// Vec grows from 0 to 4 by default on first push(). So allocate with
// capacity 1, so in the common case of only one item we don't way
// overallocate, then shrink. Note that we always push at least one
// item if parsing succeeds.
let mut position_x = Vec::with_capacity(1);
let mut position_y = Vec::with_capacity(1);
// overallocate. Note that we always push at least one item if parsing
// succeeds.
let mut position_x = background_position_x::SpecifiedValue(Vec::with_capacity(1));
let mut position_y = background_position_y::SpecifiedValue(Vec::with_capacity(1));
let mut any = false;
input.parse_comma_separated(|input| {
let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?;
position_x.push(value.horizontal);
position_y.push(value.vertical);
position_x.0.push(value.horizontal);
position_y.0.push(value.vertical);
any = true;
Ok(())
})?;
@ -222,8 +227,8 @@
}
Ok(expanded! {
background_position_x: background_position_x::SpecifiedValue(position_x.into()),
background_position_y: background_position_y::SpecifiedValue(position_y.into()),
background_position_x: position_x,
background_position_y: position_y,
})
}

View File

@ -137,7 +137,7 @@ macro_rules! try_parse_one {
Ok(expanded! {
% for prop in "property duration timing_function delay".split():
transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s.into()),
transition_${prop}: transition_${prop}::SpecifiedValue(${prop}s),
% endfor
})
}
@ -266,7 +266,7 @@ macro_rules! try_parse_one {
Ok(expanded! {
% for prop in props:
animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s.into()),
animation_${prop}: animation_${prop}::SpecifiedValue(${prop}s),
% endfor
})
}

View File

@ -42,11 +42,11 @@
input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> {
% for name in "image mode position_x position_y size repeat origin clip composite".split():
// Vec grows from 0 to 4 by default on first push(). So allocate with
// capacity 1, so in the common case of only one item we don't way
// overallocate, then shrink. Note that we always push at least one
// item if parsing succeeds.
let mut mask_${name} = Vec::with_capacity(1);
// Vec grows from 0 to 4 by default on first push(). So allocate
// with capacity 1, so in the common case of only one item we don't
// way overallocate. Note that we always push at least one item if
// parsing succeeds.
let mut mask_${name} = mask_${name}::SpecifiedValue(Vec::with_capacity(1));
% endfor
input.parse_comma_separated(|input| {
@ -96,17 +96,17 @@
% endfor
if any {
if let Some(position) = position {
mask_position_x.push(position.horizontal);
mask_position_y.push(position.vertical);
mask_position_x.0.push(position.horizontal);
mask_position_y.0.push(position.vertical);
} else {
mask_position_x.push(PositionComponent::zero());
mask_position_y.push(PositionComponent::zero());
mask_position_x.0.push(PositionComponent::zero());
mask_position_y.0.push(PositionComponent::zero());
}
% for name in "image mode size repeat origin clip composite".split():
if let Some(m_${name}) = ${name} {
mask_${name}.push(m_${name});
mask_${name}.0.push(m_${name});
} else {
mask_${name}.push(mask_${name}::single_value
mask_${name}.0.push(mask_${name}::single_value
::get_initial_specified_value());
}
% endfor
@ -118,7 +118,7 @@
Ok(expanded! {
% for name in "image mode position_x position_y size repeat origin clip composite".split():
mask_${name}: mask_${name}::SpecifiedValue(mask_${name}.into()),
mask_${name}: mask_${name},
% endfor
})
}
@ -209,16 +209,16 @@
) -> Result<Longhands, ParseError<'i>> {
// Vec grows from 0 to 4 by default on first push(). So allocate with
// capacity 1, so in the common case of only one item we don't way
// overallocate, then shrink. Note that we always push at least one
// item if parsing succeeds.
let mut position_x = Vec::with_capacity(1);
let mut position_y = Vec::with_capacity(1);
// overallocate. Note that we always push at least one item if parsing
// succeeds.
let mut position_x = mask_position_x::SpecifiedValue(Vec::with_capacity(1));
let mut position_y = mask_position_y::SpecifiedValue(Vec::with_capacity(1));
let mut any = false;
input.parse_comma_separated(|input| {
let value = Position::parse(context, input)?;
position_x.push(value.horizontal);
position_y.push(value.vertical);
position_x.0.push(value.horizontal);
position_y.0.push(value.vertical);
any = true;
Ok(())
})?;
@ -227,10 +227,9 @@
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(expanded! {
mask_position_x: mask_position_x::SpecifiedValue(position_x.into()),
mask_position_y: mask_position_y::SpecifiedValue(position_y.into()),
mask_position_x: position_x,
mask_position_y: position_y,
})
}

View File

@ -9,18 +9,22 @@ use crate::values::computed::length::Length;
#[cfg(feature = "gecko")]
use crate::values::computed::url::ComputedUrl;
use crate::values::computed::{Angle, Number};
use crate::values::generics::effects::BoxShadow as GenericBoxShadow;
use crate::values::generics::effects::Filter as GenericFilter;
use crate::values::generics::effects::SimpleShadow as GenericSimpleShadow;
#[cfg(not(feature = "gecko"))]
use crate::values::Impossible;
/// An animated value for the `drop-shadow()` filter.
type AnimatedSimpleShadow = GenericSimpleShadow<Color, Length, Length>;
/// An animated value for a single `box-shadow`.
pub type BoxShadow = GenericBoxShadow<Color, Length, Length, Length>;
/// An animated value for a single `filter`.
#[cfg(feature = "gecko")]
pub type Filter = GenericFilter<Angle, Number, Length, AnimatedSimpleShadow, ComputedUrl>;
pub type Filter = GenericFilter<Angle, Number, Length, SimpleShadow, ComputedUrl>;
/// An animated value for a single `filter`.
#[cfg(not(feature = "gecko"))]
pub type Filter = GenericFilter<Angle, Number, Length, Impossible, Impossible>;
/// An animated value for the `drop-shadow()` filter.
pub type SimpleShadow = GenericSimpleShadow<Color, Length, Length>;

View File

@ -861,7 +861,7 @@ impl Animate for ComputedTransform {
// animation procedures so we treat it separately here rather than
// handling it in TransformOperation.
if procedure == Procedure::Add {
let result = self.0.iter().chain(&*other.0).cloned().collect();
let result = self.0.iter().chain(&other.0).cloned().collect::<Vec<_>>();
return Ok(Transform(result));
}
@ -898,15 +898,15 @@ impl Animate for ComputedTransform {
},
Procedure::Interpolate { progress } => {
result.push(TransformOperation::InterpolateMatrix {
from_list: Transform(this_remainder.to_vec().into()),
to_list: Transform(other_remainder.to_vec().into()),
from_list: Transform(this_remainder.to_vec()),
to_list: Transform(other_remainder.to_vec()),
progress: Percentage(progress as f32),
});
},
Procedure::Accumulate { count } => {
result.push(TransformOperation::AccumulateMatrix {
from_list: Transform(this_remainder.to_vec().into()),
to_list: Transform(other_remainder.to_vec().into()),
from_list: Transform(this_remainder.to_vec()),
to_list: Transform(other_remainder.to_vec()),
count: cmp::min(count, i32::max_value() as u64) as i32,
});
},
@ -927,8 +927,8 @@ impl Animate for ComputedTransform {
// matrix. Instead we need to wrap it in another ___Matrix type.
TransformOperation::AccumulateMatrix { .. } |
TransformOperation::InterpolateMatrix { .. } => {
let transform_list = Transform(vec![transform.clone()].into());
let identity_list = Transform(vec![identity].into());
let transform_list = Transform(vec![transform.clone()]);
let identity_list = Transform(vec![identity]);
let (from_list, to_list) = if fill_right {
(transform_list, identity_list)
} else {
@ -970,7 +970,7 @@ impl Animate for ComputedTransform {
(None, None) => {},
}
Ok(Transform(result.into()))
Ok(Transform(result))
}
}

View File

@ -26,7 +26,6 @@ use style_traits::{CssWriter, ToCss};
ToAnimatedZero,
ToResolvedValue,
)]
#[repr(C)]
pub struct Angle(CSSFloat);
impl ToCss for Angle {

View File

@ -9,19 +9,21 @@ pub use crate::values::specified::list::ListStyleType;
pub use crate::values::specified::list::MozListReversed;
pub use crate::values::specified::list::{QuotePair, Quotes};
use servo_arc::Arc;
lazy_static! {
static ref INITIAL_QUOTES: crate::ArcSlice<QuotePair> = crate::ArcSlice::from_iter(
static ref INITIAL_QUOTES: Arc<Box<[QuotePair]>> = Arc::new(
vec![
QuotePair {
opening: "\u{201c}".to_owned().into(),
closing: "\u{201d}".to_owned().into(),
opening: "\u{201c}".to_owned().into_boxed_str(),
closing: "\u{201d}".to_owned().into_boxed_str(),
},
QuotePair {
opening: "\u{2018}".to_owned().into(),
closing: "\u{2019}".to_owned().into(),
opening: "\u{2018}".to_owned().into_boxed_str(),
closing: "\u{2019}".to_owned().into_boxed_str(),
},
]
.into_iter()
.into_boxed_slice()
);
}

View File

@ -454,7 +454,8 @@ where
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
self.iter()
.map(|item| item.to_computed_value(context))
.collect()
.collect::<Vec<_>>()
.into()
}
#[inline]
@ -462,7 +463,8 @@ where
computed
.iter()
.map(T::from_computed_value)
.collect()
.collect::<Vec<_>>()
.into()
}
}

View File

@ -16,9 +16,9 @@ pub use crate::values::generics::transform::TransformStyle;
/// A single operation in a computed CSS `transform`
pub type TransformOperation =
generic::GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
generic::TransformOperation<Angle, Number, Length, Integer, LengthPercentage>;
/// A computed CSS `transform`
pub type Transform = generic::GenericTransform<TransformOperation>;
pub type Transform = generic::Transform<TransformOperation>;
/// The computed value of a CSS `<transform-origin>`
pub type TransformOrigin =
@ -540,13 +540,13 @@ impl ToAnimatedZero for Transform {
self.0
.iter()
.map(|op| op.to_animated_zero())
.collect::<Result<crate::OwnedSlice<_>, _>>()?,
.collect::<Result<Vec<_>, _>>()?,
))
}
}
/// A computed CSS `rotate`
pub type Rotate = generic::GenericRotate<Number, Angle>;
pub type Rotate = generic::Rotate<Number, Angle>;
impl Rotate {
/// Convert TransformOperation to Rotate.
@ -573,7 +573,7 @@ impl Rotate {
}
/// A computed CSS `translate`
pub type Translate = generic::GenericTranslate<LengthPercentage, Length>;
pub type Translate = generic::Translate<LengthPercentage, Length>;
impl Translate {
/// Convert TransformOperation to Translate.
@ -602,7 +602,7 @@ impl Translate {
}
/// A computed CSS `scale`
pub type Scale = generic::GenericScale<Number>;
pub type Scale = generic::Scale<Number>;
impl Scale {
/// Convert TransformOperation to Scale.

View File

@ -19,10 +19,9 @@
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub struct BoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
/// The base shadow.
pub base: GenericSimpleShadow<Color, SizeLength, BlurShapeLength>,
pub base: SimpleShadow<Color, SizeLength, BlurShapeLength>,
/// The spread radius.
pub spread: ShapeLength,
/// Whether this is an inset box shadow.
@ -31,8 +30,6 @@ pub struct GenericBoxShadow<Color, SizeLength, BlurShapeLength, ShapeLength> {
pub inset: bool,
}
pub use self::GenericBoxShadow as BoxShadow;
/// A generic value for a single `filter`.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[animation(no_bound(Url))]
@ -103,8 +100,7 @@ pub enum Filter<Angle, Factor, Length, DropShadow, Url> {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct GenericSimpleShadow<Color, SizeLength, ShapeLength> {
pub struct SimpleShadow<Color, SizeLength, ShapeLength> {
/// Color.
pub color: Color,
/// Horizontal radius.
@ -114,5 +110,3 @@ pub struct GenericSimpleShadow<Color, SizeLength, ShapeLength> {
/// Blur radius.
pub blur: ShapeLength,
}
pub use self::GenericSimpleShadow as SimpleShadow;

View File

@ -30,9 +30,8 @@ use style_traits::{CssWriter, ToCss};
ToResolvedValue,
ToShmem,
)]
#[css(comma, function = "matrix")]
#[repr(C)]
pub struct GenericMatrix<T> {
#[css(comma, function)]
pub struct Matrix<T> {
pub a: T,
pub b: T,
pub c: T,
@ -41,8 +40,6 @@ pub struct GenericMatrix<T> {
pub f: T,
}
pub use self::GenericMatrix as Matrix;
#[allow(missing_docs)]
#[cfg_attr(rustfmt, rustfmt_skip)]
#[css(comma, function = "matrix3d")]
@ -58,16 +55,13 @@ pub use self::GenericMatrix as Matrix;
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct GenericMatrix3D<T> {
pub struct Matrix3D<T> {
pub m11: T, pub m12: T, pub m13: T, pub m14: T,
pub m21: T, pub m22: T, pub m23: T, pub m24: T,
pub m31: T, pub m32: T, pub m33: T, pub m34: T,
pub m41: T, pub m42: T, pub m43: T, pub m44: T,
}
pub use self::GenericMatrix3D as Matrix3D;
#[cfg_attr(rustfmt, rustfmt_skip)]
impl<T: Into<f64>> From<Matrix<T>> for Transform3D<f64> {
#[inline]
@ -148,19 +142,17 @@ fn is_same<N: PartialEq>(x: &N, y: &N) -> bool {
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
/// A single operation in the list of a `transform` value
/// cbindgen:derive-tagged-enum-copy-constructor=true
pub enum GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>
pub enum TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
where
Angle: Zero,
LengthPercentage: Zero,
Number: PartialEq,
{
/// Represents a 2D 2x3 matrix.
Matrix(GenericMatrix<Number>),
Matrix(Matrix<Number>),
/// Represents a 3D 4x4 matrix.
Matrix3D(GenericMatrix3D<Number>),
Matrix3D(Matrix3D<Number>),
/// A 2D skew.
///
/// If the second angle is not provided it is assumed zero.
@ -240,22 +232,20 @@ where
#[allow(missing_docs)]
#[css(comma, function = "interpolatematrix")]
InterpolateMatrix {
from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
progress: computed::Percentage,
},
/// A intermediate type for accumulation of mismatched transform lists.
#[allow(missing_docs)]
#[css(comma, function = "accumulatematrix")]
AccumulateMatrix {
from_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
to_list: GenericTransform<GenericTransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
from_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
to_list: Transform<TransformOperation<Angle, Number, Length, Integer, LengthPercentage>>,
count: Integer,
},
}
pub use self::GenericTransformOperation as TransformOperation;
#[derive(
Clone,
Debug,
@ -267,11 +257,8 @@ pub use self::GenericTransformOperation as TransformOperation;
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
/// A value of the `transform` property
pub struct GenericTransform<T>(#[css(if_empty = "none", iterable)] pub crate::OwnedSlice<T>);
pub use self::GenericTransform as Transform;
pub struct Transform<T>(#[css(if_empty = "none", iterable)] pub Vec<T>);
impl<Angle, Number, Length, Integer, LengthPercentage>
TransformOperation<Angle, Number, Length, Integer, LengthPercentage>
@ -510,7 +497,7 @@ where
impl<T> Transform<T> {
/// `none`
pub fn none() -> Self {
Transform(Default::default())
Transform(vec![])
}
}
@ -542,7 +529,7 @@ impl<T: ToMatrix> Transform<T> {
let mut transform = Transform3D::<f64>::identity();
let mut contain_3d = false;
for operation in &*self.0 {
for operation in &self.0 {
let matrix = operation.to_3d_matrix(reference_box)?;
contain_3d |= operation.is_3d();
transform = transform.pre_mul(&matrix);
@ -602,11 +589,10 @@ pub fn get_normalized_vector_and_angle<T: Zero>(
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
/// A value of the `Rotate` property
///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum GenericRotate<Number, Angle> {
pub enum Rotate<Number, Angle> {
/// 'none'
None,
/// '<angle>'
@ -615,8 +601,6 @@ pub enum GenericRotate<Number, Angle> {
Rotate3D(Number, Number, Number, Angle),
}
pub use self::GenericRotate as Rotate;
/// A trait to check if the current 3D vector is parallel to the DirectionVector.
/// This is especially for serialization on Rotate.
pub trait IsParallelTo {
@ -676,11 +660,10 @@ where
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
/// A value of the `Scale` property
///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum GenericScale<Number> {
pub enum Scale<Number> {
/// 'none'
None,
/// '<number>{1,2}'
@ -689,8 +672,6 @@ pub enum GenericScale<Number> {
Scale3D(Number, Number, Number),
}
pub use self::GenericScale as Scale;
impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
@ -729,7 +710,6 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
ToResolvedValue,
ToShmem,
)]
#[repr(C, u8)]
/// A value of the `translate` property
///
/// https://drafts.csswg.org/css-transforms-2/#individual-transform-serialization:
@ -744,7 +724,7 @@ impl<Number: ToCss + PartialEq> ToCss for Scale<Number> {
/// related spec issue is https://github.com/w3c/csswg-drafts/issues/3305
///
/// <https://drafts.csswg.org/css-transforms-2/#individual-transforms>
pub enum GenericTranslate<LengthPercentage, Length>
pub enum Translate<LengthPercentage, Length>
where
LengthPercentage: Zero,
{
@ -759,8 +739,6 @@ where
Translate3D(LengthPercentage, LengthPercentage, Length),
}
pub use self::GenericTranslate as Translate;
#[allow(missing_docs)]
#[derive(
Clone,

View File

@ -174,7 +174,6 @@ impl<A: Debug, B: Debug> Debug for Either<A, B> {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct CustomIdent(pub Atom);
impl CustomIdent {

View File

@ -642,7 +642,6 @@ pub enum OverflowClipBox {
#[derive(
Clone,
Debug,
Default,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
@ -651,38 +650,38 @@ pub enum OverflowClipBox {
ToResolvedValue,
ToShmem,
)]
#[css(comma)]
#[repr(C)]
/// Provides a rendering hint to the user agent, stating what kinds of changes
/// the author expects to perform on the element.
///
/// `auto` is represented by an empty `features` list.
/// Provides a rendering hint to the user agent,
/// stating what kinds of changes the author expects
/// to perform on the element
///
/// <https://drafts.csswg.org/css-will-change/#will-change>
pub struct WillChange {
/// The features that are supposed to change.
///
/// TODO(emilio): Consider using ArcSlice since we just clone them from the
/// specified value? That'd save an allocation, which could be worth it.
#[css(iterable, if_empty = "auto")]
features: crate::OwnedSlice<CustomIdent>,
/// A bitfield with the kind of change that the value will create, based
/// on the above field.
#[css(skip)]
bits: WillChangeBits,
pub enum WillChange {
/// Expresses no particular intent
Auto,
/// <custom-ident>
#[css(comma)]
AnimateableFeatures {
/// The features that are supposed to change.
#[css(iterable)]
features: Box<[CustomIdent]>,
/// A bitfield with the kind of change that the value will create, based
/// on the above field.
#[css(skip)]
bits: WillChangeBits,
},
}
impl WillChange {
#[inline]
/// Get default value of `will-change` as `auto`
pub fn auto() -> Self {
Self::default()
pub fn auto() -> WillChange {
WillChange::Auto
}
}
bitflags! {
/// The change bits that we care about.
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[derive(MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C)]
pub struct WillChangeBits: u8 {
/// Whether the stacking context will change.
@ -747,7 +746,7 @@ impl Parse for WillChange {
.try(|input| input.expect_ident_matching("auto"))
.is_ok()
{
return Ok(Self::default());
return Ok(WillChange::Auto);
}
let mut bits = WillChangeBits::empty();
@ -768,8 +767,8 @@ impl Parse for WillChange {
Ok(ident)
})?;
Ok(Self {
features: custom_idents.into(),
Ok(WillChange::AnimateableFeatures {
features: custom_idents.into_boxed_slice(),
bits,
})
}

View File

@ -10,6 +10,7 @@ use crate::values::generics::CounterStyleOrNone;
#[cfg(feature = "gecko")]
use crate::values::CustomIdent;
use cssparser::{Parser, Token};
use servo_arc::Arc;
use style_traits::{ParseError, StyleParseErrorKind};
/// Specified and computed `list-style-type` property.
@ -95,20 +96,18 @@ impl Parse for ListStyleType {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct QuotePair {
/// The opening quote.
pub opening: crate::OwnedStr,
pub opening: Box<str>,
/// The closing quote.
pub closing: crate::OwnedStr,
pub closing: Box<str>,
}
/// Specified and computed `quotes` property.
#[derive(
Clone,
Debug,
Default,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
@ -117,11 +116,10 @@ pub struct QuotePair {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct Quotes(
#[css(iterable, if_empty = "none")]
#[ignore_malloc_size_of = "Arc"]
pub crate::ArcSlice<QuotePair>,
pub Arc<Box<[QuotePair]>>,
);
impl Parse for Quotes {
@ -133,26 +131,24 @@ impl Parse for Quotes {
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(Self::default());
return Ok(Quotes(Arc::new(Box::new([]))));
}
let mut quotes = Vec::new();
loop {
let location = input.current_source_location();
let opening = match input.next() {
Ok(&Token::QuotedString(ref value)) => {
value.as_ref().to_owned().into()
},
Ok(&Token::QuotedString(ref value)) => value.as_ref().to_owned().into_boxed_str(),
Ok(t) => return Err(location.new_unexpected_token_error(t.clone())),
Err(_) => break,
};
let closing = input.expect_string()?.as_ref().to_owned().into();
let closing = input.expect_string()?.as_ref().to_owned().into_boxed_str();
quotes.push(QuotePair { opening, closing });
}
if !quotes.is_empty() {
Ok(Quotes(crate::ArcSlice::from_iter(quotes.into_iter())))
Ok(Quotes(Arc::new(quotes.into_boxed_slice())))
} else {
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
}

View File

@ -12,7 +12,7 @@ use crate::values::specified::AllowQuirks;
use crate::values::specified::LengthPercentage;
use crate::values::specified::{NonNegativeLengthPercentage, Opacity};
use crate::values::CustomIdent;
use cssparser::{Parser, Token};
use cssparser::Parser;
use std::fmt::{self, Write};
use style_traits::{CommaWithSpace, CssWriter, ParseError, Separator};
use style_traits::{StyleParseErrorKind, ToCss};
@ -243,28 +243,11 @@ impl ToCss for SVGPaintOrder {
}
}
bitflags! {
/// The context properties we understand.
#[derive(Default, MallocSizeOf, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
#[repr(C)]
pub struct ContextPropertyBits: u8 {
/// `fill`
const FILL = 1 << 0;
/// `stroke`
const STROKE = 1 << 1;
/// `fill-opacity`
const FILL_OPACITY = 1 << 2;
/// `stroke-opacity`
const STROKE_OPACITY = 1 << 3;
}
}
/// Specified MozContextProperties value.
/// Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-context-properties)
#[derive(
Clone,
Debug,
Default,
MallocSizeOf,
PartialEq,
SpecifiedValueInfo,
@ -273,65 +256,19 @@ bitflags! {
ToResolvedValue,
ToShmem,
)]
#[repr(C)]
pub struct MozContextProperties {
#[css(iterable, if_empty = "none")]
#[ignore_malloc_size_of = "Arc"]
idents: crate::ArcSlice<CustomIdent>,
#[css(skip)]
bits: ContextPropertyBits,
}
pub struct MozContextProperties(pub CustomIdent);
impl Parse for MozContextProperties {
fn parse<'i, 't>(
_context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<MozContextProperties, ParseError<'i>> {
let mut values = vec![];
let mut bits = ContextPropertyBits::empty();
loop {
{
let location = input.current_source_location();
let ident = input.expect_ident()?;
if ident.eq_ignore_ascii_case("none") && values.is_empty() {
return Ok(Self::default());
}
let ident = CustomIdent::from_ident(
location,
ident,
&["all", "none", "auto"],
)?;
if ident.0 == atom!("fill") {
bits.insert(ContextPropertyBits::FILL);
} else if ident.0 == atom!("stroke") {
bits.insert(ContextPropertyBits::STROKE);
} else if ident.0 == atom!("fill-opacity") {
bits.insert(ContextPropertyBits::FILL_OPACITY);
} else if ident.0 == atom!("stroke-opacity") {
bits.insert(ContextPropertyBits::STROKE_OPACITY);
}
values.push(ident);
}
let location = input.current_source_location();
match input.next() {
Ok(&Token::Comma) => continue,
Err(..) => break,
Ok(other) => return Err(location.new_unexpected_token_error(other.clone())),
}
}
if values.is_empty() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
Ok(MozContextProperties {
idents: crate::ArcSlice::from_iter(values.into_iter()),
bits,
})
let location = input.current_source_location();
let i = input.expect_ident()?;
Ok(MozContextProperties(CustomIdent::from_ident(
location,
i,
&["all", "none", "auto"],
)?))
}
}

View File

@ -42,7 +42,7 @@ impl Transform {
.try(|input| input.expect_ident_matching("none"))
.is_ok()
{
return Ok(generic::Transform::none());
return Ok(generic::Transform(Vec::new()));
}
Ok(generic::Transform(Space::parse(input, |input| {
@ -218,7 +218,7 @@ impl Transform {
.new_custom_error(StyleParseErrorKind::UnexpectedFunction(function.clone()))
})
})
})?.into()))
})?))
}
}

View File

@ -18,7 +18,6 @@ app_units = "0.7"
cssparser = "0.25"
bitflags = "1.0"
euclid = "0.19"
lazy_static = "1"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = "0.1"
selectors = { path = "../selectors" }

View File

@ -5,7 +5,7 @@
//! A thin atomically-reference-counted slice.
use servo_arc::ThinArc;
use std::{iter, mem};
use std::mem;
use std::ops::Deref;
use std::ptr::NonNull;
@ -34,26 +34,12 @@ impl<T> Deref for ArcSlice<T> {
}
}
lazy_static! {
// ThinArc doesn't support alignments greater than align_of::<u64>.
static ref EMPTY_ARC_SLICE: ArcSlice<u64> = {
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, iter::empty()))
};
}
impl<T> Default for ArcSlice<T> {
#[allow(unsafe_code)]
fn default() -> Self {
debug_assert!(
mem::align_of::<T>() <= mem::align_of::<u64>(),
"Need to increase the alignment of EMPTY_ARC_SLICE"
);
unsafe {
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
mem::transmute(empty)
}
}
}
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
/// The type of the pointer is a bit of a lie, we just want to preserve the type
/// but these pointers cannot be constructed outside of this crate, so we're
/// good.
#[repr(C)]
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);
impl<T> ArcSlice<T> {
/// Creates an Arc for a slice using the given iterator to generate the
@ -63,9 +49,6 @@ impl<T> ArcSlice<T> {
where
I: Iterator<Item = T> + ExactSizeIterator,
{
if items.len() == 0 {
return Self::default();
}
ArcSlice(ThinArc::from_header_and_iter(ARC_SLICE_CANARY, items))
}
@ -80,21 +63,4 @@ impl<T> ArcSlice<T> {
mem::forget(self);
ret
}
/// Leaks an empty arc slice pointer, and returns it. Only to be used to
/// construct ArcSlices from FFI.
#[inline]
pub fn leaked_empty_ptr() -> *mut std::os::raw::c_void {
let empty: ArcSlice<_> = EMPTY_ARC_SLICE.clone();
let ptr = empty.0.ptr();
std::mem::forget(empty);
ptr as *mut _
}
}
/// The inner pointer of an ArcSlice<T>, to be sent via FFI.
/// The type of the pointer is a bit of a lie, we just want to preserve the type
/// but these pointers cannot be constructed outside of this crate, so we're
/// good.
#[repr(C)]
pub struct ForgottenArcSlicePtr<T>(NonNull<T>);

View File

@ -16,8 +16,6 @@ extern crate bitflags;
#[macro_use]
extern crate cssparser;
extern crate euclid;
#[macro_use]
extern crate lazy_static;
extern crate malloc_size_of;
#[macro_use]
extern crate malloc_size_of_derive;
@ -93,7 +91,6 @@ pub mod values;
#[macro_use]
pub mod viewport;
pub mod owned_slice;
pub mod owned_str;
pub use crate::specified_value_info::{CssType, KeywordsCollectFn, SpecifiedValueInfo};
pub use crate::values::{

View File

@ -10,7 +10,7 @@ use malloc_size_of::{MallocShallowSizeOf, MallocSizeOf, MallocSizeOfOps};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::{fmt, iter, mem, slice};
use std::{fmt, mem, slice};
use to_shmem::{SharedMemoryBuilder, ToShmem};
/// A struct that basically replaces a `Box<[T]>`, but which cbindgen can
@ -93,7 +93,7 @@ impl<T: Sized> OwnedSlice<T> {
/// Iterate over all the elements in the slice taking ownership of them.
#[inline]
pub fn into_iter(self) -> impl Iterator<Item = T> + ExactSizeIterator {
pub fn into_iter(self) -> impl Iterator<Item = T> {
self.into_vec().into_iter()
}
@ -164,10 +164,3 @@ impl<T: ToShmem + Sized> ToShmem for OwnedSlice<T> {
}
}
}
impl<T> iter::FromIterator<T> for OwnedSlice<T> {
#[inline]
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Vec::from_iter(iter).into()
}
}

View File

@ -1,53 +0,0 @@
/* 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 https://mozilla.org/MPL/2.0/. */
#![allow(unsafe_code)]
//! A replacement for `Box<str>` that has a defined layout for FFI.
use crate::owned_slice::OwnedSlice;
use std::fmt;
use std::ops::{Deref, DerefMut};
/// A struct that basically replaces a Box<str>, but with a defined layout,
/// suitable for FFI.
#[repr(C)]
#[derive(Default, Clone, PartialEq, Eq, MallocSizeOf, ToShmem)]
pub struct OwnedStr(OwnedSlice<u8>);
impl fmt::Debug for OwnedStr {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
self.deref().fmt(formatter)
}
}
impl Deref for OwnedStr {
type Target = str;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { std::str::from_utf8_unchecked(&*self.0) }
}
}
impl DerefMut for OwnedStr {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { std::str::from_utf8_unchecked_mut(&mut *self.0) }
}
}
impl From<Box<str>> for OwnedStr {
#[inline]
fn from(b: Box<str>) -> Self {
Self::from(b.into_string())
}
}
impl From<String> for OwnedStr {
#[inline]
fn from(s: String) -> Self {
OwnedStr(s.into_bytes().into())
}
}

View File

@ -5,7 +5,6 @@
//! Value information for devtools.
use crate::arc_slice::ArcSlice;
use crate::owned_slice::OwnedSlice;
use servo_arc::Arc;
use std::ops::Range;
use std::sync::Arc as StdArc;
@ -84,7 +83,6 @@ impl SpecifiedValueInfo for u16 {}
impl SpecifiedValueInfo for u32 {}
impl SpecifiedValueInfo for str {}
impl SpecifiedValueInfo for String {}
impl SpecifiedValueInfo for crate::owned_str::OwnedStr {}
#[cfg(feature = "servo")]
impl SpecifiedValueInfo for ::servo_atoms::Atom {}
@ -116,7 +114,6 @@ macro_rules! impl_generic_specified_value_info {
};
}
impl_generic_specified_value_info!(Option<T>);
impl_generic_specified_value_info!(OwnedSlice<T>);
impl_generic_specified_value_info!(Vec<T>);
impl_generic_specified_value_info!(Arc<T>);
impl_generic_specified_value_info!(StdArc<T>);

View File

@ -75,16 +75,6 @@ where
}
}
impl ToCss for crate::owned_str::OwnedStr {
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
serialize_string(self, dest)
}
}
impl ToCss for str {
#[inline]
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result

View File

@ -110,7 +110,7 @@ include = [
"Origin",
"RestyleHint",
"TouchAction",
"WillChange",
"WillChangeBits",
"TextDecorationLine",
"TextTransform",
"MozListReversed",
@ -127,14 +127,6 @@ include = [
"ArcSlice",
"ForgottenArcSlicePtr",
"HeaderWithLength",
"MozContextProperties",
"Quotes",
"BoxShadow",
"SimpleShadow",
"Transform",
"Rotate",
"Scale",
"Translate",
]
item_types = ["enums", "structs", "typedefs", "functions"]
renaming_overrides_prefixing = true
@ -191,7 +183,6 @@ renaming_overrides_prefixing = true
"CSSPixelLength" = """
inline nscoord ToAppUnits() const;
inline bool IsZero() const;
float ToCSSPixels() const { return _0; }
"""
"LengthPercentage" = """
@ -355,16 +346,20 @@ renaming_overrides_prefixing = true
ptr((T*)alignof(T)),
len(0) {}
// Should be easily implementable if wanted, but the default implementation would leak.
StyleOwnedSlice& operator=(const StyleOwnedSlice&) = delete;
StyleOwnedSlice& operator=(StyleOwnedSlice&&) = delete;
// NOTE(emilio): Could be implemented with some effort, but for now no copy.
StyleOwnedSlice(const StyleOwnedSlice& aOther) = delete;
inline StyleOwnedSlice(const StyleOwnedSlice&);
inline StyleOwnedSlice(StyleOwnedSlice&&);
inline void Clear();
inline ~StyleOwnedSlice();
~StyleOwnedSlice() {
if (!len) {
return;
}
for (size_t i : IntegerRange(len)) {
ptr[i].~T();
}
free(ptr);
ptr = (T*)alignof(T);
len = 0;
}
Span<const T> AsSpan() const {
return MakeSpan(ptr, len);
@ -374,8 +369,6 @@ renaming_overrides_prefixing = true
return AsSpan().Length();
}
bool IsEmpty() const { return Length() == 0; }
bool operator==(const StyleOwnedSlice& other) const {
return AsSpan() == other.AsSpan();
}
@ -386,59 +379,12 @@ renaming_overrides_prefixing = true
"""
"ArcSlice" = """
inline StyleArcSlice();
StyleArcSlice() = delete;
inline StyleArcSlice(const StyleArcSlice& aOther);
// Should be easily implementable if wanted, but the default implementation would leak.
StyleArcSlice& operator=(const StyleArcSlice&) = delete;
StyleArcSlice& operator=(StyleArcSlice&&) = delete;
inline explicit StyleArcSlice(const StyleForgottenArcSlicePtr<T>& aPtr);
inline ~StyleArcSlice();
inline Span<const T> AsSpan() const;
inline size_t Length() const;
inline bool IsEmpty() const;
inline bool operator==(const StyleArcSlice& other) const;
inline bool operator!=(const StyleArcSlice& other) const;
"""
"CustomIdent" = """
inline nsAtom* AsAtom() const;
"""
"Atom" = """
StyleAtom(size_t) = delete;
StyleAtom() = delete;
// NOTE(emilio): For now we don't need to expose anything else, but it'd be trivial if we wanted to.
inline bool IsStatic() const;
inline nsAtom* AsAtom() const;
inline StyleAtom(const StyleAtom& aOther);
inline ~StyleAtom();
"""
"OwnedStr" = """
inline nsDependentCSubstring AsString() const;
"""
"GenericTransform" = """
inline Span<const T> Operations() const;
inline bool IsNone() const;
"""
"GenericTransformOperation" = """
private:
// Private default constructor without initialization so that the helper
// constructor functions still work as expected. They take care of
// initializing the fields properly.
StyleGenericTransformOperation() {}
public:
"""
"Angle" = """
inline static StyleAngle Zero();
inline float ToDegrees() const;
inline double ToRadians() const;
"""

View File

@ -47,10 +47,11 @@ use style::gecko_bindings::bindings::Gecko_GetOrCreateFinalKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateInitialKeyframe;
use style::gecko_bindings::bindings::Gecko_GetOrCreateKeyframeAtStart;
use style::gecko_bindings::bindings::Gecko_HaveSeenPtr;
use style::gecko_bindings::bindings::Gecko_NewNoneTransform;
use style::gecko_bindings::structs;
use style::gecko_bindings::structs::{Element as RawGeckoElement, nsINode as RawGeckoNode};
use style::gecko_bindings::structs::{
RawServoStyleSet, RawServoAuthorStyles,
RawServoQuotes, RawServoStyleSet, RawServoAuthorStyles,
RawServoCssUrlData, RawServoDeclarationBlock, RawServoMediaList,
RawServoCounterStyleRule, RawServoAnimationValue, RawServoSupportsRule,
RawServoKeyframesRule, ServoCssRules, RawServoStyleSheetContents,
@ -64,6 +65,7 @@ use style::gecko_bindings::structs::nsAtom;
use style::gecko_bindings::structs::nsCSSCounterDesc;
use style::gecko_bindings::structs::nsCSSFontDesc;
use style::gecko_bindings::structs::nsCSSPropertyID;
use style::gecko_bindings::structs::nsCSSValueSharedList;
use style::gecko_bindings::structs::nsChangeHint;
use style::gecko_bindings::structs::nsCompatibility;
use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
@ -91,12 +93,14 @@ use style::gecko_bindings::structs::ServoTraversalFlags;
use style::gecko_bindings::structs::SheetLoadData;
use style::gecko_bindings::structs::SheetLoadDataHolder;
use style::gecko_bindings::structs::SheetParsingMode;
use style::gecko_bindings::structs::StyleContentType as ContentType;
use style::gecko_bindings::structs::StyleRuleInclusion;
use style::gecko_bindings::structs::StyleSheet as DomStyleSheet;
use style::gecko_bindings::structs::URLExtraData;
use style::gecko_bindings::sugar::ownership::{FFIArcHelpers, HasArcFFI, HasFFI};
use style::gecko_bindings::sugar::ownership::{HasSimpleFFI, HasBoxFFI, Strong, Owned, OwnedOrNull};
use style::gecko_bindings::sugar::refptr::RefPtr;
use style::gecko_properties;
use style::global_style_data::{GlobalStyleData, GLOBAL_STYLE_DATA, STYLE_THREAD_POOL};
use style::invalidation::element::restyle_hints::RestyleHint;
use style::media_queries::MediaList;
@ -129,7 +133,7 @@ use style::traversal::DomTraversal;
use style::traversal_flags::{self, TraversalFlags};
use style::use_counters::UseCounters;
use style::values::animated::{Animate, Procedure, ToAnimatedZero};
use style::values::computed::{self, Context, ToComputedValue};
use style::values::computed::{self, Context, QuotePair, ToComputedValue};
use style::values::distance::ComputeSquaredDistance;
use style::values::specified;
use style::values::specified::gecko::IntersectionObserverRootMargin;
@ -787,76 +791,88 @@ pub extern "C" fn Servo_AnimationValue_Color(
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetScale(
value: &RawServoAnimationValue,
) -> *const computed::Scale {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Scale(ref value) => value,
_ => unreachable!("Expected scale"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetTranslate(
value: &RawServoAnimationValue,
) -> *const computed::Translate {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Translate(ref value) => value,
_ => unreachable!("Expected translate"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetRotate(
value: &RawServoAnimationValue,
) -> *const computed::Rotate {
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Rotate(ref value) => value,
_ => unreachable!("Expected rotate"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
value: &RawServoAnimationValue,
) -> *const computed::Transform {
list: *mut structs::RefPtr<nsCSSValueSharedList>,
) -> nsCSSPropertyID {
let list = &mut *list;
let value = AnimationValue::as_arc(&value);
match **value {
AnimationValue::Transform(ref value) => value,
_ => unreachable!("Unsupported transform animation value"),
AnimationValue::Transform(ref servo_list) => {
if servo_list.0.is_empty() {
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
} else {
gecko_properties::convert_transform(&servo_list.0, list);
}
nsCSSPropertyID::eCSSProperty_transform
},
AnimationValue::Translate(ref v) => {
if let Some(v) = v.to_transform_operation() {
gecko_properties::convert_transform(&[v], list);
} else {
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
}
nsCSSPropertyID::eCSSProperty_translate
},
AnimationValue::Rotate(ref v) => {
if let Some(v) = v.to_transform_operation() {
gecko_properties::convert_transform(&[v], list);
} else {
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
}
nsCSSPropertyID::eCSSProperty_rotate
},
AnimationValue::Scale(ref v) => {
if let Some(v) = v.to_transform_operation() {
gecko_properties::convert_transform(&[v], list);
} else {
list.set_move(RefPtr::from_addrefed(Gecko_NewNoneTransform()));
}
nsCSSPropertyID::eCSSProperty_scale
},
_ => unreachable!("Unsupported transform-like animation value"),
}
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Rotate(r: &computed::Rotate) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Rotate(r.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Translate(t: &computed::Translate) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Translate(t.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Scale(s: &computed::Scale) -> Strong<RawServoAnimationValue> {
Arc::new(AnimationValue::Scale(s.clone())).into_strong()
}
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_Transform(
list: *const computed::TransformOperation,
len: usize,
property: nsCSSPropertyID,
list: *const nsCSSValueSharedList,
) -> Strong<RawServoAnimationValue> {
use style::values::generics::transform::Transform;
use style::values::computed::transform::{Rotate, Scale, Translate};
let slice = std::slice::from_raw_parts(list, len);
Arc::new(AnimationValue::Transform(
Transform(slice.iter().cloned().collect())
)).into_strong()
let list = (&*list).mHead.as_ref();
let property = LonghandId::from_nscsspropertyid(property)
.expect("We don't have shorthand property animation value");
let transform = gecko_properties::clone_transform_from_list(list);
match property {
LonghandId::Rotate => {
let rotate = if transform.0.is_empty() {
style::values::generics::transform::Rotate::None
} else {
debug_assert_eq!(transform.0.len(), 1);
Rotate::from_transform_operation(&(transform.0)[0])
};
Arc::new(AnimationValue::Rotate(rotate)).into_strong()
},
LonghandId::Scale => {
debug_assert_eq!(transform.0.len(), 1);
Arc::new(AnimationValue::Scale(Scale::from_transform_operation(&(transform.0)[0])))
.into_strong()
},
LonghandId::Translate => {
debug_assert_eq!(transform.0.len(), 1);
Arc::new(AnimationValue::Translate(
Translate::from_transform_operation(&(transform.0)[0])
)).into_strong()
},
LonghandId::Transform => {
Arc::new(AnimationValue::Transform(transform)).into_strong()
},
_ => unreachable!("Unsupported transform-like animation value"),
}
}
#[no_mangle]
@ -2959,195 +2975,6 @@ pub unsafe extern "C" fn Servo_CounterStyleRule_GetGeneration(
read_locked_arc(rule, |rule: &CounterStyleRule| rule.generation())
}
fn symbol_to_string(s: &counter_style::Symbol) -> nsString {
match *s {
counter_style::Symbol::String(ref s) => nsString::from(&**s),
counter_style::Symbol::Ident(ref i) => nsString::from(i.0.as_slice())
}
}
// TODO(emilio): Cbindgen could be used to simplify a bunch of code here.
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetPad(
rule: &RawServoCounterStyleRule,
width: &mut i32,
symbol: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
let pad = match rule.pad() {
Some(pad) => pad,
None => return false,
};
*width = pad.0.value();
*symbol = symbol_to_string(&pad.1);
true
})
}
fn get_symbol(s: Option<&counter_style::Symbol>, out: &mut nsString) -> bool {
let s = match s {
Some(s) => s,
None => return false,
};
*out = symbol_to_string(s);
true
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetPrefix(
rule: &RawServoCounterStyleRule,
out: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
get_symbol(rule.prefix(), out)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSuffix(
rule: &RawServoCounterStyleRule,
out: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
get_symbol(rule.suffix(), out)
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetNegative(
rule: &RawServoCounterStyleRule,
prefix: &mut nsString,
suffix: &mut nsString,
) -> bool {
read_locked_arc(rule, |rule: &CounterStyleRule| {
let negative = match rule.negative() {
Some(n) => n,
None => return false,
};
*prefix = symbol_to_string(&negative.0);
*suffix = match negative.1 {
Some(ref s) => symbol_to_string(s),
None => nsString::new(),
};
true
})
}
#[repr(u8)]
pub enum IsOrdinalInRange {
Auto,
InRange,
NotInRange,
NoOrdinalSpecified,
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_IsInRange(
rule: &RawServoCounterStyleRule,
ordinal: i32,
) -> IsOrdinalInRange {
use style::counter_style::CounterBound;
read_locked_arc(rule, |rule: &CounterStyleRule| {
let range = match rule.range() {
Some(r) => r,
None => return IsOrdinalInRange::NoOrdinalSpecified,
};
if range.0.is_empty() {
return IsOrdinalInRange::Auto;
}
let in_range = range.0.iter().any(|r| {
if let CounterBound::Integer(start) = r.start {
if start.value() > ordinal {
return false;
}
}
if let CounterBound::Integer(end) = r.end {
if end.value() < ordinal {
return false;
}
}
true
});
if in_range {
IsOrdinalInRange::InRange
} else {
IsOrdinalInRange::NotInRange
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSymbols(
rule: &RawServoCounterStyleRule,
symbols: &mut style::OwnedSlice<nsString>,
) {
read_locked_arc(rule, |rule: &CounterStyleRule| {
*symbols = match rule.symbols() {
Some(s) => s.0.iter().map(symbol_to_string).collect(),
None => style::OwnedSlice::default(),
};
})
}
#[repr(C)]
pub struct AdditiveSymbol {
pub weight: i32,
pub symbol: nsString,
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetAdditiveSymbols(
rule: &RawServoCounterStyleRule,
symbols: &mut style::OwnedSlice<AdditiveSymbol>,
) {
read_locked_arc(rule, |rule: &CounterStyleRule| {
*symbols = match rule.additive_symbols() {
Some(s) => s.0.iter().map(|s| {
AdditiveSymbol {
weight: s.weight.value(),
symbol: symbol_to_string(&s.symbol),
}
}).collect(),
None => style::OwnedSlice::default(),
};
})
}
#[repr(C, u8)]
pub enum CounterSpeakAs {
None,
Auto,
Bullets,
Numbers,
Words,
Ident(*mut nsAtom),
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSpeakAs(
rule: &RawServoCounterStyleRule,
) -> CounterSpeakAs {
use style::counter_style::SpeakAs;
read_locked_arc(rule, |rule: &CounterStyleRule| {
let speak_as = match rule.speak_as() {
Some(s) => s,
None => return CounterSpeakAs::None,
};
match *speak_as {
SpeakAs::Auto => CounterSpeakAs::Auto,
SpeakAs::Bullets => CounterSpeakAs::Bullets,
SpeakAs::Numbers => CounterSpeakAs::Numbers,
SpeakAs::Words => CounterSpeakAs::Words,
SpeakAs::Other(ref other) => CounterSpeakAs::Ident(other.0.as_ptr()),
}
})
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetSystem(
rule: &RawServoCounterStyleRule,
@ -3216,6 +3043,24 @@ macro_rules! counter_style_descriptors {
$($i_desc:ident,)+
]
} => {
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptor(
rule: &RawServoCounterStyleRule,
desc: nsCSSCounterDesc,
result: &mut structs::nsCSSValue,
) {
read_locked_arc(rule, |rule: &CounterStyleRule| {
match desc {
$(nsCSSCounterDesc::$desc => {
if let Some(value) = rule.$getter() {
result.set_from(value);
}
})+
$(nsCSSCounterDesc::$i_desc => unreachable!(),)+
}
});
}
#[no_mangle]
pub unsafe extern "C" fn Servo_CounterStyleRule_GetDescriptorCssText(
rule: &RawServoCounterStyleRule,
@ -4880,7 +4725,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(
let url = SpecifiedImageUrl::parse_from_string(string.into(), &context);
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(vec![Either::Second(
Image::Url(url),
)].into()));
)]));
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
decls.push(decl, Importance::Normal);
});
@ -5364,12 +5209,6 @@ pub extern "C" fn Servo_GetAnimationValues(
}
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_GetPropertyId(value: &RawServoAnimationValue) -> nsCSSPropertyID {
let value = AnimationValue::as_arc(&value);
value.id().to_nscsspropertyid()
}
#[no_mangle]
pub extern "C" fn Servo_AnimationValue_Compute(
element: &RawGeckoElement,
@ -6464,8 +6303,52 @@ pub unsafe extern "C" fn Servo_IsCssPropertyRecordedInUseCounter(
}
#[no_mangle]
pub extern "C" fn Servo_Quotes_GetInitialValue() -> style_traits::arc_slice::ForgottenArcSlicePtr<specified::list::QuotePair> {
computed::Quotes::get_initial_value().0.forget()
pub extern "C" fn Servo_Quotes_GetInitialValue() -> Strong<RawServoQuotes> {
computed::Quotes::get_initial_value()
.0
.clone()
.into_strong()
}
#[no_mangle]
pub extern "C" fn Servo_Quotes_Equal(a: &RawServoQuotes, b: &RawServoQuotes) -> bool {
let a = Box::<[QuotePair]>::as_arc(&a);
let b = Box::<[QuotePair]>::as_arc(&b);
a == b
}
#[no_mangle]
pub unsafe extern "C" fn Servo_Quotes_GetQuote(
quotes: &RawServoQuotes,
mut depth: i32,
quote_type: ContentType,
result: *mut nsAString,
) {
debug_assert!(depth >= -1);
let quotes = Box::<[QuotePair]>::as_arc(&quotes);
// Reuse the last pair when the depth is greater than the number of
// pairs of quotes. (Also make 'quotes: none' and close-quote from
// a depth of 0 equivalent for the next test.)
if depth >= quotes.len() as i32 {
depth = quotes.len() as i32 - 1;
}
if depth == -1 {
// close-quote from a depth of 0 or 'quotes: none'
return;
}
let quote_pair = &quotes[depth as usize];
let quote = if quote_type == ContentType::OpenQuote {
&quote_pair.opening
} else {
debug_assert!(quote_type == ContentType::CloseQuote);
&quote_pair.closing
};
(*result).write_str(quote).unwrap();
}
#[no_mangle]
@ -6528,8 +6411,3 @@ pub unsafe extern "C" fn Servo_SharedMemoryBuilder_Drop(
pub unsafe extern "C" fn Servo_CloneBasicShape(v: &computed::basic_shape::BasicShape) -> *mut computed::basic_shape::BasicShape {
Box::into_raw(Box::new(v.clone()))
}
#[no_mangle]
pub unsafe extern "C" fn Servo_StyleArcSlice_EmptyPtr() -> *mut c_void {
style_traits::arc_slice::ArcSlice::<u64>::leaked_empty_ptr()
}

View File

@ -3,7 +3,7 @@ set -x -e -v
# If you update this, make sure to update the minimum version in
# build/moz.configure/bindgen.configure as well.
CBINDGEN_REVISION=23a991a5b21e89aa1dcdc70f1371be20c93ece8e # v0.8.7
CBINDGEN_REVISION=5ec5a82d268c8fe907767394ee7ad15718f3f09d # v0.8.6
TARGET="$1"
case "$(uname -s)" in