--- a/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
+++ b/js/src/devtools/rootAnalysis/analyzeHeapWrites.js
@@ -232,19 +232,16 @@ function treatAsSafeArgument(entry, varN
["Gecko_nsStyleFont_PrefillDefaultForGeneric", "aFont", null],
["Gecko_nsStyleSVG_SetContextPropertiesLength", "aSvg", null],
["Gecko_ClearAlternateValues", "aFont", null],
["Gecko_AppendAlternateValues", "aFont", null],
["Gecko_CopyAlternateValuesFrom", "aDest", null],
["Gecko_CounterStyle_GetName", "aResult", null],
["Gecko_CounterStyle_GetSingleString", "aResult", null],
["Gecko_EnsureMozBorderColors", "aBorder", null],
- ["Gecko_ClearMozBorderColors", "aBorder", null],
- ["Gecko_AppendMozBorderColors", "aBorder", null],
- ["Gecko_CopyMozBorderColors", "aDest", null],
];
for (var [entryMatch, varMatch, csuMatch] of whitelist) {
assert(entryMatch || varMatch || csuMatch);
if (entryMatch && !nameMatches(entry.name, entryMatch))
continue;
if (varMatch && !nameMatches(varName, varMatch))
continue;
if (csuMatch && (!csuName || !nameMatches(csuName, csuMatch)))
@@ -465,19 +462,16 @@ function ignoreContents(entry)
// Unable to analyze safety of linked list initialization.
"Gecko_NewCSSValueSharedList",
"Gecko_CSSValue_InitSharedList",
// Unable to trace through dataflow, but straightforward if inspected.
"Gecko_NewNoneTransform",
- // Bug 1400438
- "Gecko_AppendMozBorderColors",
-
// Need main thread assertions or other fixes.
/EffectCompositor::GetServoAnimationRule/,
/LookAndFeel::GetColor/,
];
if (entry.matches(whitelist))
return true;
if (entry.isSafeArgument(0)) {
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1400438-1.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+<style>
+div {
+ width: 100px; height: 100px;
+ border-left: 10px solid;
+ -moz-border-left-colors: red green;
+}
+</style>
+<div></div>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -496,9 +496,10 @@ load 1381323.html
asserts-if(!stylo,1) load 1388625-1.html # bug 1389286
load 1390389.html
load 1395591-1.html
load 1395715-1.html
load 1397398-1.html
load 1397398-2.html
load 1397398-3.html
load 1398500.html
+load 1400438-1.html
load 1400599-1.html
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -756,23 +756,21 @@ ConstructBorderRenderer(nsPresContext* a
Float borderWidths[4] = { Float(border.top) / oneDevPixel,
Float(border.right) / oneDevPixel,
Float(border.bottom) / oneDevPixel,
Float(border.left) / oneDevPixel };
Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);
uint8_t borderStyles[4];
nscolor borderColors[4];
- nsBorderColors* compositeColors[4];
-
- // pull out styles, colors, composite colors
+
+ // pull out styles, colors
NS_FOR_CSS_SIDES (i) {
borderStyles[i] = aStyleBorder.GetBorderStyle(i);
borderColors[i] = ourColor->CalcComplexColor(aStyleBorder.mBorderColor[i]);
- aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
}
PrintAsFormatString(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
nsIDocument* document = nullptr;
nsIContent* content = aForFrame->GetContent();
if (content) {
document = content->OwnerDoc();
@@ -782,17 +780,17 @@ ConstructBorderRenderer(nsPresContext* a
document,
aDrawTarget,
dirtyRect,
joinedBorderAreaPx,
borderStyles,
borderWidths,
bgRadii,
borderColors,
- compositeColors,
+ aStyleBorder.mBorderColors.get(),
bgColor);
}
DrawResult
nsCSSRendering::PaintBorderWithStyleBorder(nsPresContext* aPresContext,
gfxContext& aRenderingContext,
nsIFrame* aForFrame,
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -85,19 +85,16 @@ static Color MakeBorderColor(nscolor aCo
// border going inwards) and an array of line styles, calculate the
// color that that stripe of the border should be rendered in.
static Color ComputeColorForLine(uint32_t aLineIndex,
const BorderColorStyle* aBorderColorStyle,
uint32_t aBorderColorStyleCount,
nscolor aBorderColor,
nscolor aBackgroundColor);
-static Color ComputeCompositeColorForLine(uint32_t aLineIndex,
- const nsBorderColors* aBorderColors);
-
// little helper function to check if the array of 4 floats given are
// equal to the given value
static bool
CheckFourFloatsEqual(const Float *vals, Float k)
{
return (vals[0] == k &&
vals[1] == k &&
vals[2] == k &&
@@ -173,34 +170,35 @@ nsCSSBorderRenderer::nsCSSBorderRenderer
const nsIDocument* aDocument,
DrawTarget* aDrawTarget,
const Rect& aDirtyRect,
Rect& aOuterRect,
const uint8_t* aBorderStyles,
const Float* aBorderWidths,
RectCornerRadii& aBorderRadii,
const nscolor* aBorderColors,
- nsBorderColors* const* aCompositeColors,
+ const nsBorderColors* aCompositeColors,
nscolor aBackgroundColor)
: mPresContext(aPresContext),
mDocument(aDocument),
mDrawTarget(aDrawTarget),
mDirtyRect(aDirtyRect),
mOuterRect(aOuterRect),
mBorderRadii(aBorderRadii),
mBackgroundColor(aBackgroundColor)
{
PodCopy(mBorderStyles, aBorderStyles, 4);
PodCopy(mBorderWidths, aBorderWidths, 4);
PodCopy(mBorderColors, aBorderColors, 4);
- if (aCompositeColors) {
- PodCopy(mCompositeColors, aCompositeColors, 4);
- } else {
- static nsBorderColors * const noColors[4] = { nullptr };
- PodCopy(mCompositeColors, noColors, 4);
+ NS_FOR_CSS_SIDES(side) {
+ if (aCompositeColors && !(*aCompositeColors)[side].IsEmpty()) {
+ mCompositeColors[side] = &(*aCompositeColors)[side];
+ } else {
+ mCompositeColors[side] = nullptr;
+ }
}
mInnerRect = mOuterRect;
mInnerRect.Deflate(
Margin(mBorderStyles[0] != NS_STYLE_BORDER_STYLE_NONE ? mBorderWidths[0] : 0,
mBorderStyles[1] != NS_STYLE_BORDER_STYLE_NONE ? mBorderWidths[1] : 0,
mBorderStyles[2] != NS_STYLE_BORDER_STYLE_NONE ? mBorderWidths[2] : 0,
mBorderStyles[3] != NS_STYLE_BORDER_STYLE_NONE ? mBorderWidths[3] : 0));
@@ -314,19 +312,21 @@ nsCSSBorderRenderer::AreBorderSideFinalS
}
if (((1 << i) & aSides) == 0) {
continue;
}
if (mBorderStyles[firstStyle] != mBorderStyles[i] ||
mBorderColors[firstStyle] != mBorderColors[i] ||
- !nsBorderColors::Equal(mCompositeColors[firstStyle],
- mCompositeColors[i]))
+ !mCompositeColors[firstStyle] != !mCompositeColors[i] ||
+ (mCompositeColors[firstStyle] &&
+ *mCompositeColors[firstStyle] != *mCompositeColors[i])) {
return false;
+ }
}
/* Then if it's one of the two-tone styles and we're not
* just comparing the TL or BR sides */
switch (mBorderStyles[firstStyle]) {
case NS_STYLE_BORDER_STYLE_GROOVE:
case NS_STYLE_BORDER_STYLE_RIDGE:
case NS_STYLE_BORDER_STYLE_INSET:
@@ -1260,46 +1260,42 @@ ComputeColorForLine(uint32_t aLineIndex,
nscolor aBackgroundColor)
{
NS_ASSERTION(aLineIndex < aBorderColorStyleCount, "Invalid lineIndex given");
return MakeBorderColor(aBorderColor, aBackgroundColor,
aBorderColorStyle[aLineIndex]);
}
-Color
-ComputeCompositeColorForLine(uint32_t aLineIndex,
- const nsBorderColors* aBorderColors)
-{
- while (aLineIndex-- && aBorderColors->mNext)
- aBorderColors = aBorderColors->mNext;
-
- return Color::FromABGR(aBorderColors->mColor);
-}
-
void
-nsCSSBorderRenderer::DrawBorderSidesCompositeColors(int aSides, const nsBorderColors *aCompositeColors)
+nsCSSBorderRenderer::DrawBorderSidesCompositeColors(
+ int aSides, const nsTArray<nscolor>& aCompositeColors)
{
RectCornerRadii radii = mBorderRadii;
// the generic composite colors path; each border is 1px in size
Rect soRect = mOuterRect;
Float maxBorderWidth = 0;
NS_FOR_CSS_SIDES (i) {
maxBorderWidth = std::max(maxBorderWidth, Float(mBorderWidths[i]));
}
Float fakeBorderSizes[4];
Point itl = mInnerRect.TopLeft();
Point ibr = mInnerRect.BottomRight();
+ MOZ_ASSERT(!aCompositeColors.IsEmpty());
+ Color compositeColor;
for (uint32_t i = 0; i < uint32_t(maxBorderWidth); i++) {
- ColorPattern color(ToDeviceColor(
- ComputeCompositeColorForLine(i, aCompositeColors)));
+ // advance to next color if exists.
+ if (i < aCompositeColors.Length()) {
+ compositeColor = ToDeviceColor(Color::FromABGR(aCompositeColors[i]));
+ }
+ ColorPattern color(compositeColor);
Rect siRect = soRect;
siRect.Deflate(1.0);
// now cap the rects to the real mInnerRect
Point tl = siRect.TopLeft();
Point br = siRect.BottomRight();
@@ -1329,17 +1325,17 @@ nsCSSBorderRenderer::DrawBorderSides(int
{
if (aSides == 0 || (aSides & ~eSideBitsAll) != 0) {
NS_WARNING("DrawBorderSides: invalid sides!");
return;
}
uint8_t borderRenderStyle = NS_STYLE_BORDER_STYLE_NONE;
nscolor borderRenderColor;
- const nsBorderColors *compositeColors = nullptr;
+ const nsTArray<nscolor>* compositeColors = nullptr;
uint32_t borderColorStyleCount = 0;
BorderColorStyle borderColorStyleTopLeft[3], borderColorStyleBottomRight[3];
BorderColorStyle *borderColorStyle = nullptr;
NS_FOR_CSS_SIDES (i) {
if ((aSides & (1 << i)) == 0)
continue;
@@ -1387,17 +1383,17 @@ nsCSSBorderRenderer::DrawBorderSides(int
// color is used for the remainder of the border's size. Just
// hand off to another function to do all that.
if (compositeColors) {
Float maxBorderWidth(0);
NS_FOR_CSS_SIDES (i) {
maxBorderWidth = std::max(maxBorderWidth, mBorderWidths[i]);
}
if (maxBorderWidth <= MAX_COMPOSITE_BORDER_WIDTH) {
- DrawBorderSidesCompositeColors(aSides, compositeColors);
+ DrawBorderSidesCompositeColors(aSides, *compositeColors);
return;
}
NS_WARNING("DrawBorderSides: too large border width for composite colors");
}
// We're not doing compositeColors, so we can calculate the
// borderColorStyle based on the specified style. The
// borderColorStyle array goes from the outer to the inner style.
@@ -3140,80 +3136,73 @@ nsCSSBorderRenderer::DrawNoCompositeColo
firstColor, secondColor, skirtSize, skirtSlope);
}
}
}
void
nsCSSBorderRenderer::DrawRectangularCompositeColors()
{
- nsBorderColors *currentColors[4];
- memcpy(currentColors, mCompositeColors, sizeof(nsBorderColors*) * 4);
+ nscolor currentColors[4];
+ NS_FOR_CSS_SIDES(side) {
+ currentColors[side] = mBorderColors[side];
+ }
Rect rect = mOuterRect;
rect.Deflate(0.5);
const twoFloats cornerAdjusts[4] = { { +0.5, 0 },
{ 0, +0.5 },
{ -0.5, 0 },
{ 0, -0.5 } };
for (int i = 0; i < mBorderWidths[0]; i++) {
NS_FOR_CSS_SIDES(side) {
+ // advance to the next composite color if one exists
+ if (mCompositeColors[side] &&
+ uint32_t(i) < mCompositeColors[side]->Length()) {
+ currentColors[side] = (*mCompositeColors[side])[i];
+ }
+ }
+ NS_FOR_CSS_SIDES(side) {
int sideNext = (side + 1) % 4;
Point firstCorner = rect.CCWCorner(side) + cornerAdjusts[side];
Point secondCorner = rect.CWCorner(side) - cornerAdjusts[side];
- Color currentColor = Color::FromABGR(
- currentColors[side] ? currentColors[side]->mColor
- : mBorderColors[side]);
+ Color currentColor = Color::FromABGR(currentColors[side]);
mDrawTarget->StrokeLine(firstCorner, secondCorner,
ColorPattern(ToDeviceColor(currentColor)));
Point cornerTopLeft = rect.CWCorner(side) - Point(0.5, 0.5);
- Color nextColor = Color::FromABGR(
- currentColors[sideNext] ? currentColors[sideNext]->mColor
- : mBorderColors[sideNext]);
+ Color nextColor = Color::FromABGR(currentColors[sideNext]);
Color cornerColor((currentColor.r + nextColor.r) / 2.f,
(currentColor.g + nextColor.g) / 2.f,
(currentColor.b + nextColor.b) / 2.f,
(currentColor.a + nextColor.a) / 2.f);
mDrawTarget->FillRect(Rect(cornerTopLeft, Size(1, 1)),
ColorPattern(ToDeviceColor(cornerColor)));
-
- if (side != 0) {
- // We'll have to keep side 0 for the color averaging on side 3.
- if (currentColors[side] && currentColors[side]->mNext) {
- currentColors[side] = currentColors[side]->mNext;
- }
- }
- }
- // Now advance the color for side 0.
- if (currentColors[0] && currentColors[0]->mNext) {
- currentColors[0] = currentColors[0]->mNext;
}
rect.Deflate(1);
}
}
void
nsCSSBorderRenderer::DrawBorders()
{
bool forceSeparateCorners = false;
if (mAllBordersSameStyle &&
((mCompositeColors[0] == nullptr &&
(mBorderStyles[0] == NS_STYLE_BORDER_STYLE_NONE ||
mBorderStyles[0] == NS_STYLE_BORDER_STYLE_HIDDEN ||
mBorderColors[0] == NS_RGBA(0,0,0,0))) ||
- (mCompositeColors[0] &&
- (mCompositeColors[0]->mColor == NS_RGBA(0,0,0,0) &&
- !mCompositeColors[0]->mNext))))
+ (mCompositeColors[0] && mCompositeColors[0]->Length() == 1 &&
+ (*mCompositeColors[0])[0] == NS_RGBA(0,0,0,0))))
{
// All borders are the same style, and the style is either none or hidden, or the color
// is transparent.
// This also checks if the first composite color is transparent, and there are
// no others. It doesn't check if there are subsequent transparent ones, because
// that would be very silly.
return;
}
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -95,17 +95,17 @@ public:
const nsIDocument* aDocument,
DrawTarget* aDrawTarget,
const Rect& aDirtyRect,
Rect& aOuterRect,
const uint8_t* aBorderStyles,
const Float* aBorderWidths,
RectCornerRadii& aBorderRadii,
const nscolor* aBorderColors,
- nsBorderColors* const* aCompositeColors,
+ const nsBorderColors* aCompositeColors,
nscolor aBackgroundColor);
// draw the entire border
void DrawBorders();
bool CanCreateWebRenderCommands();
void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
@@ -146,17 +146,19 @@ private:
uint8_t mBorderStyles[4];
Float mBorderWidths[4];
RectCornerRadii mBorderRadii;
// the colors for 'border-top-color' et. al.
nscolor mBorderColors[4];
// the lists of colors for '-moz-border-top-colors' et. al.
- nsBorderColors* mCompositeColors[4];
+ // the pointers here are either nullptr, or referring to a non-empty
+ // nsTArray, so no additional empty check is needed.
+ const nsTArray<nscolor>* mCompositeColors[4];
// the background color
nscolor mBackgroundColor;
// calculated values
bool mAllBordersSameStyle;
bool mAllBordersSameWidth;
bool mOneUnitBorder;
@@ -230,17 +232,18 @@ private:
// core rendering
//
// draw the border for the given sides, using the style of the first side
// present in the bitmask
void DrawBorderSides (int aSides);
// function used by the above to handle -moz-border-colors
- void DrawBorderSidesCompositeColors(int aSides, const nsBorderColors *compositeColors);
+ void DrawBorderSidesCompositeColors(
+ int aSides, const nsTArray<nscolor>& compositeColors);
// Setup the stroke options for the given dashed/dotted side
void SetupDashedOptions(StrokeOptions* aStrokeOptions,
Float aDash[2], mozilla::Side aSide,
Float aBorderLength, bool isCorner);
// Draw the given dashed/dotte side
void DrawDashedOrDottedSide(mozilla::Side aSide);
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1251,44 +1251,16 @@ Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom*
}
void
Gecko_EnsureMozBorderColors(nsStyleBorder* aBorder)
{
aBorder->EnsureBorderColors();
}
-void Gecko_ClearMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide)
-{
- aBorder->ClearBorderColors(aSide);
-}
-
-void
-Gecko_AppendMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide,
- nscolor aColor)
-{
- aBorder->AppendBorderColor(aSide, aColor);
-}
-
-void
-Gecko_CopyMozBorderColors(nsStyleBorder* aDest, const nsStyleBorder* aSrc,
- mozilla::Side aSide)
-{
- if (aSrc->mBorderColors) {
- aDest->CopyBorderColorsFrom(aSrc->mBorderColors[aSide], aSide);
- }
-}
-
-const nsBorderColors*
-Gecko_GetMozBorderColors(const nsStyleBorder* aBorder, mozilla::Side aSide)
-{
- MOZ_ASSERT(aBorder);
- return aBorder->mBorderColors ? aBorder->mBorderColors[aSide] : nullptr;
-}
-
void
Gecko_FontFamilyList_Clear(FontFamilyList* aList) {
aList->Clear();
}
void
Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName, bool aQuoted)
{
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -277,23 +277,16 @@ nsIAtom* Gecko_Atomize16(const nsAString
void Gecko_AddRefAtom(nsIAtom* aAtom);
void Gecko_ReleaseAtom(nsIAtom* aAtom);
const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
// Border style
void Gecko_EnsureMozBorderColors(nsStyleBorder* aBorder);
-void Gecko_ClearMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide);
-void Gecko_AppendMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide,
- nscolor aColor);
-void Gecko_CopyMozBorderColors(nsStyleBorder* aDest, const nsStyleBorder* aSrc,
- mozilla::Side aSide);
-const nsBorderColors* Gecko_GetMozBorderColors(const nsStyleBorder* aBorder,
- mozilla::Side aSide);
// Font style
void Gecko_FontFamilyList_Clear(FontFamilyList* aList);
void Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName, bool aQuoted);
void Gecko_FontFamilyList_AppendGeneric(FontFamilyList* list, FontFamilyType familyType);
void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src);
// will not run destructors on dst, give it uninitialized memory
// font_id is LookAndFeel::FontID
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -185,17 +185,16 @@ whitelist-types = [
"gfxFontVariation",
"GridNamedArea",
"HalfCorner",
"Image",
"ImageURL",
"Keyframe",
"nsAttrName",
"nsAttrValue",
- "nsBorderColors",
"nscolor",
"nsChangeHint",
"nsCSSCounterDesc",
"nsCSSCounterStyleRule",
"nsCSSFontFaceRule",
"nsCSSKeyword",
"nsCSSPropertyID",
"nsCSSPropertyIDSet",
@@ -384,17 +383,16 @@ structs-types = [
"mozilla::css::GridTemplateAreasValue",
"mozilla::css::ErrorReporter",
"mozilla::css::ImageValue",
"mozilla::css::URLValue",
"mozilla::css::URLValueData",
"mozilla::AnonymousCounterStyle",
"mozilla::MallocSizeOf",
"mozilla::OriginFlags",
- "mozilla::Side",
"mozilla::UniquePtr",
"ServoRawOffsetArc",
"nsIContent",
"nsIDocument",
"nsIDocument_DocumentTheme",
"RawGeckoAnimationPropertySegment",
"RawGeckoComputedTiming",
"RawGeckoCSSPropertyIDList",
@@ -438,17 +436,16 @@ structs-types = [
"ServoElementSnapshotTable",
"ServoStyleSetSizes",
"SheetParsingMode",
"StyleBasicShape",
"StyleBasicShapeType",
"StyleShapeSource",
"StyleTransition",
"gfxFontFeatureValueSet",
- "nsBorderColors",
"nsCSSCounterStyleRule",
"nsCSSFontFaceRule",
"nsCSSKeyword",
"nsCSSPropertyID",
"nsCSSPropertyIDSet",
"nsCSSShadowArray",
"nsCSSUnit",
"nsCSSValue",
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -5485,29 +5485,24 @@ nsComputedDOMStyle::GetLineHeightCoord(n
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::GetBorderColorsFor(mozilla::Side aSide)
{
const nsStyleBorder *border = StyleBorder();
if (border->mBorderColors) {
- nsBorderColors* borderColors = border->mBorderColors[aSide];
- if (borderColors) {
+ const nsTArray<nscolor>& borderColors = (*border->mBorderColors)[aSide];
+ if (!borderColors.IsEmpty()) {
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
-
- do {
+ for (nscolor color : borderColors) {
RefPtr<nsROCSSPrimitiveValue> primitive = new nsROCSSPrimitiveValue;
-
- SetToRGBAColor(primitive, borderColors->mColor);
-
+ SetToRGBAColor(primitive, color);
valueList->AppendCSSValue(primitive.forget());
- borderColors = borderColors->mNext;
- } while (borderColors);
-
+ }
return valueList.forget();
}
}
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(eCSSKeyword_none);
return val.forget();
}
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -7743,38 +7743,35 @@ nsRuleNode::ComputeBorderData(void* aSta
case eCSSUnit_Unset:
case eCSSUnit_None:
border->ClearBorderColors(side);
break;
case eCSSUnit_Inherit: {
conditions.SetUncacheable();
border->ClearBorderColors(side);
- if (parentContext) {
- nsBorderColors *parentColors;
- parentBorder->GetCompositeColors(side, &parentColors);
- if (parentColors) {
- border->EnsureBorderColors();
- border->mBorderColors[side] = parentColors->Clone();
- }
+ if (parentBorder->mBorderColors) {
+ border->EnsureBorderColors();
+ border->mBorderColors->mColors[side] =
+ parentBorder->mBorderColors->mColors[side];
}
break;
}
case eCSSUnit_List:
case eCSSUnit_ListDep: {
// Some composite border color information has been specified for this
// border side.
border->EnsureBorderColors();
border->ClearBorderColors(side);
const nsCSSValueList* list = value.GetListValue();
while (list) {
if (SetColor(list->mValue, unused, mPresContext,
aContext, borderColor, conditions))
- border->AppendBorderColor(side, borderColor);
+ border->mBorderColors->mColors[side].AppendElement(borderColor);
else {
NS_NOTREACHED("unexpected item in -moz-border-*-colors list");
}
list = list->mNext;
}
break;
}
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -315,18 +315,17 @@ nsStylePadding::CalcDifference(const nsS
// FIXME: It would be good to return a weaker hint here that doesn't
// force reflow of all descendants, but the hint would need to force
// reflow of the frame's children (see how
// ReflowInput::InitResizeFlags initializes the inline-resize flag).
return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
}
nsStyleBorder::nsStyleBorder(const nsPresContext* aContext)
- : mBorderColors(nullptr)
- , mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL)
+ : mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL)
, mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
, mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
, mFloatEdge(StyleFloatEdge::ContentBox)
, mBoxDecorationBreak(StyleBoxDecorationBreak::Slice)
, mComputedBorder(0, 0, 0, 0)
{
MOZ_COUNT_CTOR(nsStyleBorder);
@@ -344,72 +343,45 @@ nsStyleBorder::nsStyleBorder(const nsPre
mBorder.Side(side) = medium;
mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE;
mBorderColor[side] = StyleComplexColor::CurrentColor();
}
mTwipsPerPixel = aContext->DevPixelsToAppUnits(1);
}
-nsBorderColors::~nsBorderColors()
-{
- NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
-}
-
-nsBorderColors*
-nsBorderColors::Clone(bool aDeep) const
-{
- nsBorderColors* result = new nsBorderColors(mColor);
- if (MOZ_UNLIKELY(!result)) {
- return result;
- }
- if (aDeep) {
- NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
- }
- return result;
-}
-
nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
- : mBorderColors(nullptr)
- , mBorderRadius(aSrc.mBorderRadius)
+ : mBorderRadius(aSrc.mBorderRadius)
, mBorderImageSource(aSrc.mBorderImageSource)
, mBorderImageSlice(aSrc.mBorderImageSlice)
, mBorderImageWidth(aSrc.mBorderImageWidth)
, mBorderImageOutset(aSrc.mBorderImageOutset)
, mBorderImageFill(aSrc.mBorderImageFill)
, mBorderImageRepeatH(aSrc.mBorderImageRepeatH)
, mBorderImageRepeatV(aSrc.mBorderImageRepeatV)
, mFloatEdge(aSrc.mFloatEdge)
, mBoxDecorationBreak(aSrc.mBoxDecorationBreak)
, mComputedBorder(aSrc.mComputedBorder)
, mBorder(aSrc.mBorder)
, mTwipsPerPixel(aSrc.mTwipsPerPixel)
{
MOZ_COUNT_CTOR(nsStyleBorder);
if (aSrc.mBorderColors) {
- NS_FOR_CSS_SIDES(side) {
- CopyBorderColorsFrom(aSrc.mBorderColors[side], side);
- }
+ mBorderColors.reset(new nsBorderColors(*aSrc.mBorderColors));
}
NS_FOR_CSS_SIDES(side) {
mBorderStyle[side] = aSrc.mBorderStyle[side];
mBorderColor[side] = aSrc.mBorderColor[side];
}
}
nsStyleBorder::~nsStyleBorder()
{
MOZ_COUNT_DTOR(nsStyleBorder);
- if (mBorderColors) {
- for (int32_t i = 0; i < 4; i++) {
- delete mBorderColors[i];
- }
- delete [] mBorderColors;
- }
}
void
nsStyleBorder::FinishStyle(nsPresContext* aPresContext)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
@@ -511,19 +483,18 @@ nsStyleBorder::CalcDifference(const nsSt
mBorderImageWidth != aNewData.mBorderImageWidth) {
return nsChangeHint_RepaintFrame;
}
}
// Note that at this point if mBorderColors is non-null so is
// aNewData.mBorderColors
if (mBorderColors) {
- NS_FOR_CSS_SIDES(ix) {
- if (!nsBorderColors::Equal(mBorderColors[ix],
- aNewData.mBorderColors[ix])) {
+ NS_FOR_CSS_SIDES(side) {
+ if ((*mBorderColors)[side] != (*aNewData.mBorderColors)[side]) {
return nsChangeHint_RepaintFrame;
}
}
}
// mBorder is the specified border value. Changes to this don't
// need any change processing, since we operate on the computed
// border values instead.
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -979,48 +979,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
NS_FOR_CSS_SIDES(side) {
// Clamp negative calc() to 0.
aPadding.Side(side) = std::max(mPadding.ToLength(side), 0);
}
return true;
}
};
-struct nsBorderColors
-{
- nsBorderColors* mNext;
- nscolor mColor;
-
- nsBorderColors() : mNext(nullptr), mColor(NS_RGB(0,0,0)) {}
- explicit nsBorderColors(const nscolor& aColor) : mNext(nullptr), mColor(aColor) {}
- ~nsBorderColors();
-
- nsBorderColors* Clone() const { return Clone(true); }
-
- static bool Equal(const nsBorderColors* c1,
- const nsBorderColors* c2) {
- if (c1 == c2) {
- return true;
- }
- while (c1 && c2) {
- if (c1->mColor != c2->mColor) {
- return false;
- }
- c1 = c1->mNext;
- c2 = c2->mNext;
- }
- // both should be nullptr if these are equal, otherwise one
- // has more colors than another
- return !c1 && !c2;
- }
-
-private:
- nsBorderColors* Clone(bool aDeep) const;
-};
-
struct nsCSSShadowItem
{
nscoord mXOffset;
nscoord mYOffset;
nscoord mRadius;
nscoord mSpread;
nscolor mColor;
@@ -1137,16 +1105,36 @@ private:
// Returns if the given border style type is visible or not
static bool IsVisibleBorderStyle(uint8_t aStyle)
{
return (aStyle != NS_STYLE_BORDER_STYLE_NONE &&
aStyle != NS_STYLE_BORDER_STYLE_HIDDEN);
}
+struct nsBorderColors
+{
+ nsBorderColors() = default;
+
+ // GCC cannot generate this copy constructor correctly, since nsTArray
+ // has explicit copy constructor, and we use array of nsTArray here.
+ // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82235
+ nsBorderColors(const nsBorderColors& aOther) {
+ NS_FOR_CSS_SIDES(side) {
+ mColors[side] = aOther.mColors[side];
+ }
+ }
+
+ const nsTArray<nscolor>& operator[](mozilla::Side aSide) const {
+ return mColors[aSide];
+ }
+
+ nsTArray<nscolor> mColors[4];
+};
+
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder
{
explicit nsStyleBorder(const nsPresContext* aContext);
nsStyleBorder(const nsStyleBorder& aBorder);
~nsStyleBorder();
// Resolves and tracks mBorderImageSource. Only called with a Servo-backed
// style system, where those images must be resolved later than the OMT
@@ -1160,37 +1148,23 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
AllocateByObjectID(mozilla::eArenaObjectID_nsStyleBorder, sz);
}
void Destroy(nsPresContext* aContext);
nsChangeHint CalcDifference(const nsStyleBorder& aNewData) const;
void EnsureBorderColors() {
if (!mBorderColors) {
- mBorderColors = new nsBorderColors*[4];
- if (mBorderColors) {
- for (int32_t i = 0; i < 4; i++) {
- mBorderColors[i] = nullptr;
- }
- }
+ mBorderColors.reset(new nsBorderColors);
}
}
void ClearBorderColors(mozilla::Side aSide) {
- if (mBorderColors && mBorderColors[aSide]) {
- delete mBorderColors[aSide];
- mBorderColors[aSide] = nullptr;
- }
- }
-
- void CopyBorderColorsFrom(const nsBorderColors* aSrcBorderColors, mozilla::Side aSide) {
- if (aSrcBorderColors) {
- EnsureBorderColors();
- ClearBorderColors(aSide);
- mBorderColors[aSide] = aSrcBorderColors->Clone();
+ if (mBorderColors) {
+ mBorderColors->mColors[aSide].Clear();
}
}
// Return whether aStyle is a visible style. Invisible styles cause
// the relevant computed border width to be 0.
// Note that this does *not* consider the effects of 'border-image':
// if border-style is none, but there is a loaded border image,
// HasVisibleStyle will be false even though there *is* a border.
@@ -1255,50 +1229,27 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
{
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
mBorderImageSource.ResolveImage(aContext);
}
}
nsMargin GetImageOutset() const;
- void GetCompositeColors(int32_t aIndex, nsBorderColors** aColors) const
- {
- if (!mBorderColors) {
- *aColors = nullptr;
- } else {
- *aColors = mBorderColors[aIndex];
- }
- }
-
- void AppendBorderColor(int32_t aIndex, nscolor aColor)
- {
- NS_ASSERTION(aIndex >= 0 && aIndex <= 3, "bad side for composite border color");
- nsBorderColors* colorEntry = new nsBorderColors(aColor);
- if (!mBorderColors[aIndex]) {
- mBorderColors[aIndex] = colorEntry;
- } else {
- nsBorderColors* last = mBorderColors[aIndex];
- while (last->mNext) {
- last = last->mNext;
- }
- last->mNext = colorEntry;
- }
- }
-
imgIRequest* GetBorderImageRequest() const
{
if (mBorderImageSource.GetType() == eStyleImageType_Image) {
return mBorderImageSource.GetImageData();
}
return nullptr;
}
public:
- nsBorderColors** mBorderColors; // [reset] composite (stripe) colors
+ // [reset] composite (stripe) colors
+ mozilla::UniquePtr<nsBorderColors> mBorderColors;
nsStyleCorners mBorderRadius; // [reset] coord, percent
nsStyleImage mBorderImageSource; // [reset]
nsStyleSides mBorderImageSlice; // [reset] factor, percent
nsStyleSides mBorderImageWidth; // [reset] length, factor, percent, auto
nsStyleSides mBorderImageOutset; // [reset] length, factor
uint8_t mBorderImageFill; // [reset]
uint8_t mBorderImageRepeatH; // [reset] see nsStyleConsts.h
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -1267,16 +1267,60 @@ fn static_assert() {
<% skip_moz_border_color_longhands = " ".join("-moz-border-{0}-colors".format(x.ident)
for x in SIDES) %>
<%self:impl_trait style_struct_name="Border"
skip_longhands="${skip_border_longhands} border-image-source border-image-outset
border-image-repeat border-image-width border-image-slice
${skip_moz_border_color_longhands}">
+ fn set_moz_border_colors(&mut self, side: structs::Side, v: Option<Vec<::cssparser::RGBA>>) {
+ match v {
+ None => {
+ let ptr = self.gecko.mBorderColors.mPtr;
+ if let Some(colors) = unsafe { ptr.as_mut() } {
+ unsafe { colors.mColors[side as usize].clear() };
+ }
+ }
+ Some(ref colors) => {
+ unsafe { bindings::Gecko_EnsureMozBorderColors(&mut self.gecko) };
+ let border_colors = unsafe { self.gecko.mBorderColors.mPtr.as_mut().unwrap() };
+ let dest_colors = &mut border_colors.mColors[side as usize];
+ unsafe { dest_colors.set_len_pod(colors.len() as u32) };
+ for (dst, src) in dest_colors.iter_mut().zip(colors.into_iter()) {
+ *dst = convert_rgba_to_nscolor(src);
+ }
+ }
+ }
+ }
+
+ fn copy_moz_border_colors_from(&mut self, other: &Self, side: structs::Side) {
+ if let Some(dest) = unsafe { self.gecko.mBorderColors.mPtr.as_mut() } {
+ dest.mColors[side as usize].clear_pod();
+ }
+ if let Some(src) = unsafe { other.gecko.mBorderColors.mPtr.as_ref() } {
+ let src = &src.mColors[side as usize];
+ if !src.is_empty() {
+ unsafe { bindings::Gecko_EnsureMozBorderColors(&mut self.gecko) };
+ let dest = unsafe { self.gecko.mBorderColors.mPtr.as_mut().unwrap() };
+ let dest = &mut dest.mColors[side as usize];
+ unsafe { dest.set_len_pod(src.len() as u32) };
+ dest.copy_from_slice(&src);
+ }
+ }
+ }
+
+ fn clone_moz_border_colors(&self, side: structs::Side) -> Option<Vec<::cssparser::RGBA>> {
+ unsafe { self.gecko.mBorderColors.mPtr.as_ref() }.map(|colors| {
+ colors.mColors[side as usize].iter()
+ .map(|color| convert_nscolor_to_rgba(*color))
+ .collect()
+ })
+ }
+
% for side in SIDES:
<% impl_keyword("border_%s_style" % side.ident,
"mBorderStyle[%s]" % side.index,
border_style_keyword,
on_set="update_border_%s" % side.ident) %>
// This is needed because the initial mComputedBorder value is set to zero.
//
@@ -1317,76 +1361,34 @@ fn static_assert() {
pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
self.gecko.mComputedBorder.${side.ident} != 0
}
#[allow(non_snake_case)]
pub fn set__moz_border_${side.ident}_colors(&mut self,
v: longhands::_moz_border_${side.ident}_colors::computed_value::T) {
- match v.0 {
- None => {
- unsafe {
- bindings::Gecko_ClearMozBorderColors(&mut self.gecko,
- structs::Side::eSide${to_camel_case(side.ident)});
- }
- },
- Some(ref colors) => {
- unsafe {
- bindings::Gecko_EnsureMozBorderColors(&mut self.gecko);
- bindings::Gecko_ClearMozBorderColors(&mut self.gecko,
- structs::Side::eSide${to_camel_case(side.ident)});
- }
- for color in colors {
- let c = convert_rgba_to_nscolor(color);
- unsafe {
- bindings::Gecko_AppendMozBorderColors(&mut self.gecko,
- structs::Side::eSide${to_camel_case(side.ident)},
- c);
- }
- }
- }
- }
+ self.set_moz_border_colors(structs::Side::eSide${to_camel_case(side.ident)}, v.0);
}
#[allow(non_snake_case)]
pub fn copy__moz_border_${side.ident}_colors_from(&mut self, other: &Self) {
- unsafe {
- bindings::Gecko_CopyMozBorderColors(&mut self.gecko, &other.gecko,
- structs::Side::eSide${to_camel_case(side.ident)});
- }
+ self.copy_moz_border_colors_from(other, structs::Side::eSide${to_camel_case(side.ident)});
}
#[allow(non_snake_case)]
pub fn reset__moz_border_${side.ident}_colors(&mut self, other: &Self) {
self.copy__moz_border_${side.ident}_colors_from(other)
}
#[allow(non_snake_case)]
pub fn clone__moz_border_${side.ident}_colors(&self)
-> longhands::_moz_border_${side.ident}_colors::computed_value::T {
use self::longhands::_moz_border_${side.ident}_colors::computed_value::T;
-
- let mut gecko_colors =
- unsafe { bindings::Gecko_GetMozBorderColors(&self.gecko,
- structs::Side::eSide${to_camel_case(side.ident)}) };
-
- if gecko_colors.is_null() {
- return T(None);
- }
-
- let mut colors = Vec::new();
- loop {
- unsafe {
- colors.push(convert_nscolor_to_rgba((*gecko_colors).mColor));
- if (*gecko_colors).mNext.is_null() { break; }
- gecko_colors = (*gecko_colors).mNext;
- }
- }
- T(Some(colors))
+ T(self.clone_moz_border_colors(structs::Side::eSide${to_camel_case(side.ident)}))
}
% endfor
% for corner in CORNERS:
<% impl_corner_style_coord("border_%s_radius" % corner.ident,
"mBorderRadius",
corner.x_index,
corner.y_index) %>