Merge remote-tracking branch 'origin/tracking' into custom

This commit is contained in:
roytam1 2025-07-29 10:44:33 +08:00
commit 4c1a4a4402
31 changed files with 827 additions and 36 deletions

View file

@ -1270,6 +1270,12 @@ ComputeSelectorStateDependence(nsCSSSelector& aSelector)
continue;
}
if (pseudoClass->mType == CSSPseudoClassType::autofill ||
pseudoClass->mType == CSSPseudoClassType::mozAutofillHighlight) {
states |= NS_EVENT_STATE_AUTOFILL;
continue;
}
auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
states |= nsCSSPseudoClasses::sPseudoClassStateDependences[idx];
}

View file

@ -198,6 +198,7 @@ CSS_KEY(collapse, collapse)
CSS_KEY(color, color)
CSS_KEY(color-burn, color_burn)
CSS_KEY(color-dodge, color_dodge)
CSS_KEY(color-mix, color_mix)
CSS_KEY(common-ligatures, common_ligatures)
CSS_KEY(column, column)
CSS_KEY(column-reverse, column_reverse)
@ -313,6 +314,7 @@ CSS_KEY(horizontal, horizontal)
CSS_KEY(horizontal-tb, horizontal_tb)
CSS_KEY(hue, hue)
CSS_KEY(hue-rotate, hue_rotate)
CSS_KEY(hsl, hsl)
CSS_KEY(hz, hz)
CSS_KEY(icon, icon)
CSS_KEY(ignore, ignore)

View file

@ -7444,6 +7444,110 @@ CSSParserImpl::ParseColor(nsCSSValue& aValue)
}
break;
case eCSSToken_Function: {
// check for color-mix function
if (mToken.mIdent.LowerCaseEqualsLiteral("color-mix")) {
// parse color-mix function
if (!GetToken(true)) {
SkipUntil(')');
return CSSParseResult::Error;
}
if (mToken.mType != eCSSToken_Ident || !mToken.mIdent.LowerCaseEqualsLiteral("in")) {
SkipUntil(')');
return CSSParseResult::Error;
}
// Check for supported color spaces: srgb or hsl
if (!GetToken(true) || mToken.mType != eCSSToken_Ident) {
SkipUntil(')');
return CSSParseResult::Error;
}
mozilla::css::ColorMixColorSpace colorSpace;
if (mToken.mIdent.LowerCaseEqualsLiteral("srgb")) {
colorSpace = mozilla::css::ColorMixColorSpace::sRGB;
} else if (mToken.mIdent.LowerCaseEqualsLiteral("hsl")) {
colorSpace = mozilla::css::ColorMixColorSpace::HSL;
} else {
SkipUntil(')');
return CSSParseResult::Error;
}
if (!ExpectSymbol(',', true)) {
SkipUntil(')');
return CSSParseResult::Error;
}
nsCSSValue color1;
if (ParseColor(color1) != CSSParseResult::Ok) {
SkipUntil(')');
return CSSParseResult::Error;
}
// parse optional weight for first color
bool w1_specified = false;
float w1 = 0.5f; // Default to 50%
if (GetToken(true)) {
if (mToken.mType == eCSSToken_Percentage) {
w1 = mToken.mNumber; // percentage tokens are already normalized (0.0-1.0)
w1_specified = true;
// Reject invalid percentages (outside 0-100% range)
if (w1 < 0.0f || w1 > 1.0f) {
SkipUntil(')');
return CSSParseResult::Error;
}
} else {
UngetToken();
}
}
if (!ExpectSymbol(',', true)) {
SkipUntil(')');
return CSSParseResult::Error;
}
nsCSSValue color2;
if (ParseColor(color2) != CSSParseResult::Ok) {
SkipUntil(')');
return CSSParseResult::Error;
}
// parse optional weight for second color
bool w2_specified = false;
float w2 = 0.5f; // default to 50%
if (GetToken(true)) {
if (mToken.mType == eCSSToken_Percentage) {
w2 = mToken.mNumber; // percentage tokens are already normalized (0.0-1.0)
w2_specified = true;
// Reject invalid percentages (outside 0-100% range)
if (w2 < 0.0f || w2 > 1.0f) {
SkipUntil(')');
return CSSParseResult::Error;
}
} else {
UngetToken();
}
}
if (w1_specified && !w2_specified) {
// first specified, second should be complement
w2 = 1.0f - w1;
} else if (!w1_specified && w2_specified) {
// second specified, first should be complement
w1 = 1.0f - w2;
}
if (!ExpectSymbol(')', true)) {
SkipUntil(')');
return CSSParseResult::Error;
}
RefPtr<mozilla::css::ColorMixValue> colorMix = new mozilla::css::ColorMixValue(
colorSpace, color1, color2, w1, w2);
aValue.SetColorMixValue(colorMix.forget());
return CSSParseResult::Ok;
}
bool isRGB;
bool isHSL;
if ((isRGB = mToken.mIdent.LowerCaseEqualsLiteral("rgb")) ||
@ -8650,7 +8754,8 @@ CSSParserImpl::ParseVariant(nsCSSValue& aValue,
(tk->mIdent.LowerCaseEqualsLiteral("rgb") ||
tk->mIdent.LowerCaseEqualsLiteral("hsl") ||
tk->mIdent.LowerCaseEqualsLiteral("rgba") ||
tk->mIdent.LowerCaseEqualsLiteral("hsla"))))
tk->mIdent.LowerCaseEqualsLiteral("hsla") ||
tk->mIdent.LowerCaseEqualsLiteral("color-mix"))))
{
// Put token back so that parse color can get it
UngetToken();

View file

@ -194,6 +194,9 @@ CSS_STATE_PSEUDO_CLASS(mozFullScreen, ":-moz-full-screen", 0, "", NS_EVENT_STATE
CSS_STATE_PSEUDO_CLASS(modal, ":modal", 0, "", NS_EVENT_STATE_MODAL_DIALOG)
CSS_STATE_PSEUDO_CLASS(mozModalDialog, ":-moz-modal-dialog", 0, "", NS_EVENT_STATE_MODAL_DIALOG)
// Matches autofilled input elements
CSS_STATE_PSEUDO_CLASS(autofill, ":autofill", 0, "", NS_EVENT_STATE_AUTOFILL)
// Matches if the element is focused and should show a focus ring
CSS_STATE_PSEUDO_CLASS(mozFocusRing, ":-moz-focusring", 0, "", NS_EVENT_STATE_FOCUSRING)
@ -274,6 +277,9 @@ CSS_STATE_PSEUDO_CLASS(mozMeterSubSubOptimum, ":-moz-meter-sub-sub-optimum", 0,
// Those values should be parsed but do nothing.
CSS_STATE_PSEUDO_CLASS(mozPlaceholder, ":-moz-placeholder", 0, "", NS_EVENT_STATE_IGNORE)
// Internal-only pseudo-class for autofill highlight
CSS_STATE_PSEUDO_CLASS(mozAutofillHighlight, ":-moz-autofill-highlight", CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS, "", NS_EVENT_STATE_AUTOFILL)
#ifdef DEFINED_CSS_STATE_PSEUDO_CLASS
#undef DEFINED_CSS_STATE_PSEUDO_CLASS
#undef CSS_STATE_PSEUDO_CLASS

View file

@ -16,6 +16,7 @@
#include "PLDHashTable.h"
#include "nsICSSPseudoComparator.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/css/ImportRule.h"
#include "mozilla/css/StyleRule.h"
#include "mozilla/css/GroupRule.h"
#include "nsIDocument.h"
@ -649,6 +650,12 @@ CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
if (!layer->mData->mCounterStyleRules.AppendElement(counterStyleRule)) {
return false;
}
} else if (css::Rule::IMPORT_RULE == type &&
nsCSSRuleUtils::LoadImportedSheetsInOrderEnabled()) {
css::ImportRule* importRule = static_cast<css::ImportRule*>(aRule);
nsCSSRuleProcessor::CascadeSheet(
importRule->GetStyleSheet()->AsConcrete(),
layer);
}
return true;
}
@ -660,10 +667,12 @@ nsCSSRuleProcessor::CascadeSheet(CSSStyleSheet* aSheet, CascadeLayer* aLayer)
aSheet->UseForPresentation(aLayer->mPresContext,
aLayer->mCacheKey) &&
aSheet->mInner) {
CSSStyleSheet* child = aSheet->mInner->mFirstChild;
while (child) {
CascadeSheet(child, aLayer);
child = child->mNext;
if (!nsCSSRuleUtils::LoadImportedSheetsInOrderEnabled()) {
CSSStyleSheet* child = aSheet->mInner->mFirstChild;
while (child) {
CascadeSheet(child, aLayer);
child = child->mNext;
}
}
if (!aSheet->mInner->mOrderedRules.EnumerateForwards(CascadeRuleEnumFunc,

View file

@ -154,13 +154,13 @@ public:
bool IsInRuleProcessorCache() const { return mInRuleProcessorCache; }
bool IsUsedByMultipleStyleSets() const { return mStyleSetRefCnt > 1; }
static bool CascadeSheet(mozilla::CSSStyleSheet* aSheet,
CascadeLayer* aLayer);
protected:
virtual ~nsCSSRuleProcessor();
private:
static bool CascadeSheet(mozilla::CSSStyleSheet* aSheet,
CascadeLayer* aLayer);
RuleProcessorGroup* GetGroup(nsPresContext* aPresContext);
void RefreshGroup(nsPresContext* aPresContext);

View file

@ -19,6 +19,7 @@ using namespace mozilla::dom;
#define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
static bool gSupportVisitedPseudo = true;
static bool gLoadImportedSheetsInOrder = true;
static nsTArray<nsCOMPtr<nsIAtom>>* sSystemMetrics = 0;
@ -31,6 +32,9 @@ nsCSSRuleUtils::Startup()
{
Preferences::AddBoolVarCache(
&gSupportVisitedPseudo, VISITED_PSEUDO_PREF, true);
Preferences::AddBoolVarCache(&gLoadImportedSheetsInOrder,
"layout.css.load-imported-sheets-in-order",
true);
}
static bool
@ -206,6 +210,12 @@ nsCSSRuleUtils::HasSystemMetric(nsIAtom* aMetric)
return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
}
/* static */ bool
nsCSSRuleUtils::LoadImportedSheetsInOrderEnabled()
{
return gLoadImportedSheetsInOrder;
}
#ifdef XP_WIN
/* static */ uint8_t
nsCSSRuleUtils::GetWindowsThemeIdentifier()
@ -566,6 +576,14 @@ nsCSSRuleUtils::StateSelectorMatches(Element* aElement,
for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
pseudoClass;
pseudoClass = pseudoClass->mNext) {
if (pseudoClass->mType == CSSPseudoClassType::autofill ||
pseudoClass->mType == CSSPseudoClassType::mozAutofillHighlight) {
// Match if the element has the autofill state, regardless of focus
if (!aElement->State().HasState(NS_EVENT_STATE_AUTOFILL)) {
return false;
}
continue; // This pseudo-class matches
}
auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
EventStates statesToCheck = nsCSSPseudoClasses::sPseudoClassStates[idx];
if (!statesToCheck.IsEmpty() && !StateSelectorMatches(aElement,

View file

@ -27,6 +27,8 @@ struct nsCSSRuleUtils
static void FreeSystemMetrics();
static bool HasSystemMetric(nsIAtom* aMetric);
static bool LoadImportedSheetsInOrderEnabled();
#ifdef XP_WIN
// Cached theme identifier for the moz-windows-theme media query.
static uint8_t GetWindowsThemeIdentifier();

View file

@ -166,6 +166,10 @@ nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
mValue.mComplexColor = aCopy.mValue.mComplexColor;
mValue.mComplexColor->AddRef();
}
else if (eCSSUnit_ColorMix == mUnit) {
mValue.mColorMix = aCopy.mValue.mColorMix;
mValue.mColorMix->AddRef();
}
else if (eCSSUnit_Revert == mUnit) {
mValue.mCascadeOrigin = aCopy.mValue.mCascadeOrigin;
}
@ -282,6 +286,14 @@ bool nsCSSValue::operator==(const nsCSSValue& aOther) const
else if (eCSSUnit_ComplexColor == mUnit) {
return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
}
else if (eCSSUnit_ColorMix == mUnit) {
return mValue.mColorMix == aOther.mValue.mColorMix ||
(mValue.mColorMix->mColorSpace == aOther.mValue.mColorMix->mColorSpace &&
mValue.mColorMix->mColor1 == aOther.mValue.mColorMix->mColor1 &&
mValue.mColorMix->mColor2 == aOther.mValue.mColorMix->mColor2 &&
mValue.mColorMix->mWeight1 == aOther.mValue.mColorMix->mWeight1 &&
mValue.mColorMix->mWeight2 == aOther.mValue.mColorMix->mWeight2);
}
else if (eCSSUnit_Revert == mUnit) {
return mValue.mCascadeOrigin == aOther.mValue.mCascadeOrigin;
}
@ -421,6 +433,8 @@ void nsCSSValue::DoReset()
mValue.mFloatColor->Release();
} else if (eCSSUnit_ComplexColor == mUnit) {
mValue.mComplexColor->Release();
} else if (eCSSUnit_ColorMix == mUnit) {
mValue.mColorMix->Release();
} else if (UnitHasArrayValue()) {
mValue.mArray->Release();
} else if (eCSSUnit_URL == mUnit) {
@ -545,6 +559,14 @@ nsCSSValue::SetComplexColorValue(already_AddRefed<ComplexColorValue> aValue)
mValue.mComplexColor = aValue.take();
}
void
nsCSSValue::SetColorMixValue(already_AddRefed<ColorMixValue> aValue)
{
Reset();
mUnit = eCSSUnit_ColorMix;
mValue.mColorMix = aValue.take();
}
void
nsCSSValue::SetCascadeOriginValue(mozilla::SheetType aValue, nsCSSUnit aUnit)
{
@ -1709,6 +1731,28 @@ nsCSSValue::AppendToString(nsCSSPropertyID aProperty, nsAString& aResult,
}
serializable.AppendToString(aProperty, aResult, aSerialization);
}
else if (eCSSUnit_ColorMix == unit) {
const ColorMixValue* colorMix = GetColorMixValue();
aResult.AppendLiteral("color-mix(in ");
// append color space
switch (colorMix->mColorSpace) {
case mozilla::css::ColorMixColorSpace::sRGB:
aResult.AppendLiteral("srgb");
break;
case mozilla::css::ColorMixColorSpace::HSL:
aResult.AppendLiteral("hsl");
break;
}
// append color1 and color2
aResult.AppendLiteral(", ");
colorMix->mColor1.AppendToString(aProperty, aResult, aSerialization);
aResult.AppendLiteral(", ");
colorMix->mColor2.AppendToString(aProperty, aResult, aSerialization);
aResult.Append(')');
}
else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
aResult.AppendLiteral("url(");
nsStyleUtil::AppendEscapedCSSString(
@ -2007,6 +2051,7 @@ nsCSSValue::AppendToString(nsCSSPropertyID aProperty, nsAString& aResult,
case eCSSUnit_HSLColor: break;
case eCSSUnit_HSLAColor: break;
case eCSSUnit_ComplexColor: break;
case eCSSUnit_ColorMix: break;
case eCSSUnit_Percent: aResult.Append(char16_t('%')); break;
case eCSSUnit_Number: break;
case eCSSUnit_Gradient: break;
@ -2221,6 +2266,11 @@ nsCSSValue::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
n += mValue.mComplexColor->SizeOfIncludingThis(aMallocSizeOf);
break;
// Color Mix
case eCSSUnit_ColorMix:
n += mValue.mColorMix->SizeOfIncludingThis(aMallocSizeOf);
break;
// Cascade Origin: nothing extra to measure.
case eCSSUnit_Revert:
break;
@ -3075,6 +3125,18 @@ css::ComplexColorValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
return n;
}
size_t
css::ColorMixValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
// Only measure it if it's unshared, to avoid double-counting.
size_t n = 0;
if (mRefCnt <= 1) {
n += aMallocSizeOf(this);
n += mColor1.SizeOfExcludingThis(aMallocSizeOf);
n += mColor2.SizeOfExcludingThis(aMallocSizeOf);
}
return n;
}
nsCSSValueGradientStop::nsCSSValueGradientStop()
: mLocation(eCSSUnit_None),
mColor(eCSSUnit_Null),

View file

@ -521,6 +521,7 @@ enum nsCSSUnit {
eCSSUnit_HSLColor = 89, // (nsCSSValueFloatColor*)
eCSSUnit_HSLAColor = 90, // (nsCSSValueFloatColor*)
eCSSUnit_ComplexColor = 91, // (ComplexColorValue*)
eCSSUnit_ColorMix = 92, // (ColorMixValue*)
eCSSUnit_Percent = 100, // (float) 1.0 == 100%) value is percentage of something
eCSSUnit_Number = 101, // (float) value is numeric (usually multiplier, different behavior than percent)
@ -606,6 +607,13 @@ struct nsCSSValueTriplet;
struct nsCSSValueTriplet_heap;
class nsCSSValueFloatColor;
namespace mozilla {
namespace css {
enum class ColorMixColorSpace;
struct ColorMixValue;
} // namespace css
} // namespace mozilla
class nsCSSValue {
public:
struct Array;
@ -804,6 +812,12 @@ public:
MOZ_ASSERT(mUnit == eCSSUnit_ComplexColor);
return mValue.mComplexColor->ToComplexColor();
}
mozilla::css::ColorMixValue* GetColorMixValue() const
{
MOZ_ASSERT(mUnit == eCSSUnit_ColorMix);
return mValue.mColorMix;
}
Array* GetArrayValue() const
{
@ -950,6 +964,8 @@ public:
void SetRGBAColorValue(const mozilla::css::RGBAColorData& aValue);
void SetComplexColorValue(
already_AddRefed<mozilla::css::ComplexColorValue> aValue);
void SetColorMixValue(
already_AddRefed<mozilla::css::ColorMixValue> aValue);
void SetCascadeOriginValue(mozilla::SheetType aValue, nsCSSUnit aUnit);
void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
void SetURLValue(mozilla::css::URLValue* aURI);
@ -1063,6 +1079,7 @@ protected:
nsCSSValueFloatColor* MOZ_OWNING_REF mFloatColor;
mozilla::css::FontFamilyListRefCnt* MOZ_OWNING_REF mFontFamilyList;
mozilla::css::ComplexColorValue* MOZ_OWNING_REF mComplexColor;
mozilla::css::ColorMixValue* MOZ_OWNING_REF mColorMix;
mozilla::SheetType mCascadeOrigin;
} mValue;
};
@ -1972,5 +1989,41 @@ protected:
static const corner_type corners[4];
};
namespace mozilla {
namespace css {
enum class ColorMixColorSpace {
sRGB,
HSL
};
struct ColorMixValue final
{
ColorMixColorSpace mColorSpace;
nsCSSValue mColor1;
nsCSSValue mColor2;
float mWeight1;
float mWeight2;
ColorMixValue(ColorMixColorSpace aColorSpace, const nsCSSValue& aColor1, const nsCSSValue& aColor2)
: mColorSpace(aColorSpace), mColor1(aColor1), mColor2(aColor2), mWeight1(0.5f), mWeight2(0.5f) {}
ColorMixValue(ColorMixColorSpace aColorSpace, const nsCSSValue& aColor1, const nsCSSValue& aColor2,
float aWeight1, float aWeight2)
: mColorSpace(aColorSpace), mColor1(aColor1), mColor2(aColor2), mWeight1(aWeight1), mWeight2(aWeight2) {}
ColorMixValue(const ColorMixValue&) = delete;
NS_INLINE_DECL_REFCOUNTING(ColorMixValue)
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
private:
~ColorMixValue() {}
};
} // namespace css
} // namespace mozilla
#endif /* nsCSSValue_h___ */

View file

@ -1137,6 +1137,165 @@ static bool SetColor(const nsCSSValue& aValue, const nscolor aParentColor,
aResult = aParentColor;
result = true;
aConditions.SetUncacheable();
} else if (eCSSUnit_ColorMix == unit) {
const mozilla::css::ColorMixValue* colorMix = aValue.GetColorMixValue();
if (colorMix) {
nscolor color1, color2;
if (SetColor(colorMix->mColor1, aParentColor, aPresContext, aContext, color1, aConditions) &&
SetColor(colorMix->mColor2, aParentColor, aPresContext, aContext, color2, aConditions)) {
// interpolate each RGBA component with proper percentage handling
float w1 = colorMix->mWeight1;
float w2 = colorMix->mWeight2;
// edge case: if both weights are zero, return transparent black
if (w1 <= 0.0f && w2 <= 0.0f) {
aResult = NS_RGBA(0, 0, 0, 0);
result = true;
} else {
// normalize weights
float sum = w1 + w2;
if (sum <= 0.0f) {
// both weights zero - use equal weighting
w1 = w2 = 0.5f;
sum = 1.0f;
}
float norm1 = w1 / sum;
float norm2 = w2 / sum;
if (colorMix->mColorSpace == mozilla::css::ColorMixColorSpace::HSL) {
// HSL color space mixing
float h1, s1, l1, h2, s2, l2;
float a1 = NS_GET_A(color1) / 255.0f;
float a2 = NS_GET_A(color2) / 255.0f;
// Convert RGB colors to HSL
NS_RGB2HSL(NS_GET_R(color1), NS_GET_G(color1), NS_GET_B(color1), &h1, &s1, &l1);
NS_RGB2HSL(NS_GET_R(color2), NS_GET_G(color2), NS_GET_B(color2), &h2, &s2, &l2);
float h, s, l, a;
// check if both are opaque
if (a1 >= 1.0f && a2 >= 1.0f) {
if (s1 == 0.0f || s2 == 0.0f) {
h = (s1 == 0.0f) ? h2 : h1;
} else {
float hue_diff = h2 - h1;
if (hue_diff > 0.5f) {
h1 += 1.0f;
} else if (hue_diff < -0.5f) {
h2 += 1.0f;
}
h = h1 * norm1 + h2 * norm2;
if (h >= 1.0f) h -= 1.0f;
}
// interpolate saturation and lightness normally
s = s1 * norm1 + s2 * norm2;
l = l1 * norm1 + l2 * norm2;
a = 1.0f; // Result is opaque
} else {
// handle alpha premultiplication for HSL components when transparency is involved
float alpha1_weight = norm1 * a1;
float alpha2_weight = norm2 * a2;
float total_alpha_weight = alpha1_weight + alpha2_weight;
if (total_alpha_weight <= 0.0f) {
// both colors are fully transparent
h = s = l = 0.0f;
a = 0.0f;
} else {
// normalize alpha-weighted contributions
float norm_alpha1 = alpha1_weight / total_alpha_weight;
float norm_alpha2 = alpha2_weight / total_alpha_weight;
// handle hue interpolation (circular)
if (s1 == 0.0f || s2 == 0.0f) {
h = (s1 == 0.0f) ? h2 : h1;
} else {
float hue_diff = h2 - h1;
if (hue_diff > 0.5f) {
h1 += 1.0f;
} else if (hue_diff < -0.5f) {
h2 += 1.0f;
}
h = h1 * norm_alpha1 + h2 * norm_alpha2;
if (h >= 1.0f) h -= 1.0f;
}
// interpolate saturation and lightness with alpha weighting
s = s1 * norm_alpha1 + s2 * norm_alpha2;
l = l1 * norm_alpha1 + l2 * norm_alpha2;
// interpolate alpha normally (without premultiplication)
a = a1 * norm1 + a2 * norm2;
}
}
// Convert back to RGB
nscolor hslResult = NS_HSL2RGB(h, s, l);
uint8_t aInt = (uint8_t)mozilla::clamped(a * 255.0f + 0.5f, 0.0f, 255.0f);
aResult = NS_RGBA(NS_GET_R(hslResult), NS_GET_G(hslResult), NS_GET_B(hslResult), aInt);
result = true;
} else {
// sRGB color space mixing with proper alpha premultiplication
float r1 = NS_GET_R(color1);
float g1 = NS_GET_G(color1);
float b1 = NS_GET_B(color1);
float a1 = NS_GET_A(color1) / 255.0f;
float r2 = NS_GET_R(color2);
float g2 = NS_GET_G(color2);
float b2 = NS_GET_B(color2);
float a2 = NS_GET_A(color2) / 255.0f;
float r, g, b, a;
// Check if both colors are opaque - use simple interpolation
if (a1 >= 1.0f && a2 >= 1.0f) {
// Simple linear interpolation for opaque colors
r = r1 * norm1 + r2 * norm2;
g = g1 * norm1 + g2 * norm2;
b = b1 * norm1 + b2 * norm2;
a = 1.0f; // Result is opaque
} else {
// handle alpha premultiplication for RGB components when transparency is involved
float alpha1_weight = norm1 * a1;
float alpha2_weight = norm2 * a2;
float total_alpha_weight = alpha1_weight + alpha2_weight;
if (total_alpha_weight <= 0.0f) {
// both colors are fully transparent
r = g = b = a = 0.0f;
} else {
// normalize alpha-weighted contributions
float norm_alpha1 = alpha1_weight / total_alpha_weight;
float norm_alpha2 = alpha2_weight / total_alpha_weight;
// interpolate RGB components with alpha weighting
r = r1 * norm_alpha1 + r2 * norm_alpha2;
g = g1 * norm_alpha1 + g2 * norm_alpha2;
b = b1 * norm_alpha1 + b2 * norm_alpha2;
// interpolate alpha normally (without premultiplication)
a = a1 * norm1 + a2 * norm2;
}
}
// convert to integers with rounding
uint8_t rInt = (uint8_t)mozilla::clamped(r + 0.5f, 0.0f, 255.0f);
uint8_t gInt = (uint8_t)mozilla::clamped(g + 0.5f, 0.0f, 255.0f);
uint8_t bInt = (uint8_t)mozilla::clamped(b + 0.5f, 0.0f, 255.0f);
uint8_t aInt = (uint8_t)mozilla::clamped(a * 255.0f + 0.5f, 0.0f, 255.0f);
aResult = NS_RGBA(rInt, gInt, bInt, aInt);
result = true;
}
}
}
}
} else if (eCSSUnit_Enumerated == unit &&
aValue.GetIntValue() == NS_STYLE_COLOR_INHERIT_FROM_BODY) {
NS_ASSERTION(aPresContext->CompatibilityMode() == eCompatibility_NavQuirks,

View file

@ -106,6 +106,14 @@ input {
overflow-clip-box: content-box;
}
/* Autofill highlight - placed immediately after base input styles */
input:-moz-autofill-highlight,
select:-moz-autofill-highlight,
textarea:-moz-autofill-highlight {
background-color: #fffcd0 !important;
color: #090909;
}
input > .anonymous-div,
input::placeholder {
word-wrap: normal !important;
@ -1148,4 +1156,4 @@ input[type="number"] > div > div > div:hover {
input[type="date"],
input[type="time"] {
overflow: hidden !important;
}
}