mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 09:07:30 +09:00
Merge remote-tracking branch 'origin/tracking' into custom
This commit is contained in:
commit
4c1a4a4402
31 changed files with 827 additions and 36 deletions
|
|
@ -3381,7 +3381,9 @@ exports.CSS_PROPERTIES = {
|
|||
"word-spacing",
|
||||
"overflow-wrap",
|
||||
"writing-mode",
|
||||
"z-index"
|
||||
"z-index",
|
||||
"overflow-block",
|
||||
"overflow-inline"
|
||||
],
|
||||
"supports": [
|
||||
1,
|
||||
|
|
@ -3411,7 +3413,6 @@ exports.CSS_PROPERTIES = {
|
|||
"-moz-grid-line",
|
||||
"-moz-groupbox",
|
||||
"-moz-gtk-info-bar",
|
||||
"clip",
|
||||
"-moz-image-rect",
|
||||
"-moz-inline-box",
|
||||
"-moz-inline-grid",
|
||||
|
|
@ -3502,6 +3503,7 @@ exports.CSS_PROPERTIES = {
|
|||
"checkbox-container",
|
||||
"checkbox-label",
|
||||
"checkmenuitem",
|
||||
"clip",
|
||||
"clone",
|
||||
"collapse",
|
||||
"color",
|
||||
|
|
@ -8568,6 +8570,42 @@ exports.CSS_PROPERTIES = {
|
|||
"visible"
|
||||
]
|
||||
},
|
||||
"overflow-block": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"overflow-block"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"auto",
|
||||
"clip",
|
||||
"hidden",
|
||||
"inherit",
|
||||
"initial",
|
||||
"revert",
|
||||
"scroll",
|
||||
"unset",
|
||||
"visible"
|
||||
]
|
||||
},
|
||||
"overflow-inline": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"overflow-inline"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"auto",
|
||||
"clip",
|
||||
"hidden",
|
||||
"inherit",
|
||||
"initial",
|
||||
"revert",
|
||||
"scroll",
|
||||
"unset",
|
||||
"visible"
|
||||
]
|
||||
},
|
||||
"overflow-wrap": {
|
||||
"isInherited": true,
|
||||
"subproperties": [
|
||||
|
|
|
|||
|
|
@ -1603,6 +1603,16 @@ private:
|
|||
|
||||
// Data members
|
||||
EventStates mState;
|
||||
|
||||
public:
|
||||
// Public helper to add or remove event states
|
||||
void SetEventState(mozilla::EventStates aState, bool aAdd) {
|
||||
if (aAdd) {
|
||||
this->AddStates(aState);
|
||||
} else {
|
||||
this->RemoveStates(aState);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class RemoveFromBindingManagerRunnable : public mozilla::Runnable
|
||||
|
|
|
|||
|
|
@ -4058,3 +4058,35 @@ nsTranslationNodeList::GetLength(uint32_t* aRetVal)
|
|||
*aRetVal = mLength;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::AddElementEventState(nsIDOMElement* aElement, uint64_t aState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||
if (!content) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mozilla::dom::Element* element = static_cast<mozilla::dom::Element*>(content.get());
|
||||
if (!element) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
element->SetEventState(mozilla::EventStates(aState), true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::RemoveElementEventState(nsIDOMElement* aElement, uint64_t aState)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aElement);
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
||||
if (!content) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
mozilla::dom::Element* element = static_cast<mozilla::dom::Element*>(content.get());
|
||||
if (!element) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
element->SetEventState(mozilla::EventStates(aState), false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,6 +293,9 @@ private:
|
|||
// Modal <dialog> element
|
||||
#define NS_EVENT_STATE_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(54)
|
||||
|
||||
// Autofilled input element (for :autofill pseudo-class)
|
||||
#define NS_EVENT_STATE_AUTOFILL NS_DEFINE_EVENT_STATE_MACRO(55)
|
||||
|
||||
#define DIR_ATTR_STATES (NS_EVENT_STATE_HAS_DIR_ATTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_LTR | \
|
||||
NS_EVENT_STATE_DIR_ATTR_RTL | \
|
||||
|
|
|
|||
|
|
@ -2832,6 +2832,20 @@ HTMLInputElement::SetUserInput(const nsAString& aValue)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (aAutofilled) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue = value;
|
||||
} else {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
nsIEditor*
|
||||
HTMLInputElement::GetEditor()
|
||||
{
|
||||
|
|
@ -3562,7 +3576,18 @@ HTMLInputElement::Blur(ErrorResult& aError)
|
|||
}
|
||||
|
||||
nsGenericHTMLElement::Blur(aError);
|
||||
}
|
||||
|
||||
if (State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
// Force a complete restyle to ensure autofill pseudo-classes are processed
|
||||
if (nsIDocument* doc = GetComposedDoc()) {
|
||||
if (nsIPresShell* shell = doc->GetShell()) {
|
||||
if (nsIFrame* frame = GetPrimaryFrame()) {
|
||||
shell->FrameNeedsReflow(frame, nsIPresShell::eStyleChange, NS_FRAME_IS_DIRTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::Focus(ErrorResult& aError)
|
||||
|
|
@ -7070,6 +7095,13 @@ HTMLInputElement::IntrinsicState() const
|
|||
state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
|
||||
}
|
||||
|
||||
// Autofill highlight should persist as long as the value matches the autofilled value
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
if (!mAutofilledValue.IsEmpty() && value == mAutofilledValue) {
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
|
@ -8505,8 +8537,23 @@ HTMLInputElement::InitializeKeyboardEventListeners()
|
|||
NS_IMETHODIMP_(void)
|
||||
HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value);
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// Only remove autofilled state if the value actually changed from autofilled value
|
||||
if (aWasInteractiveUserChange && State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue != value) {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
} else if (aWasInteractiveUserChange && !State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
// If the value is changed back to the autofilled value, restore the state
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue == value) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAllValidityStates(aNotify);
|
||||
|
||||
if (HasDirAuto()) {
|
||||
|
|
@ -8537,6 +8584,24 @@ HTMLInputElement::HasCachedSelection()
|
|||
return isCached;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::BeginProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLInputElement::EndProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLInputElement::FieldSetDisabledChanged(bool aNotify)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@ public:
|
|||
}
|
||||
|
||||
NS_IMETHOD SetUserInput(const nsAString& aInput) override;
|
||||
NS_IMETHOD BeginProgrammaticValueSet() override;
|
||||
NS_IMETHOD EndProgrammaticValueSet() override;
|
||||
|
||||
// Overriden nsIFormControl methods
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return mType; }
|
||||
|
|
@ -845,6 +847,15 @@ public:
|
|||
void SetUserInput(const nsAString& aInput,
|
||||
nsIPrincipal& aSubjectPrincipal);
|
||||
|
||||
/**
|
||||
* Sets or clears the autofilled state of this input element.
|
||||
* When setting, also stores the autofilled value for persistence.
|
||||
* When clearing, clears the stored autofilled value.
|
||||
*
|
||||
* @param aAutofilled Whether the element should be marked as autofilled
|
||||
*/
|
||||
void SetAutofilled(bool aAutofilled);
|
||||
|
||||
// XPCOM GetPhonetic() is OK
|
||||
|
||||
/**
|
||||
|
|
@ -860,6 +871,8 @@ public:
|
|||
|
||||
void UpdateEntries(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories);
|
||||
|
||||
void SetAutofilledValue(const nsAString& aValue) { mAutofilledValue = aValue; }
|
||||
|
||||
protected:
|
||||
virtual ~HTMLInputElement();
|
||||
|
||||
|
|
@ -1103,7 +1116,7 @@ protected:
|
|||
bool MinOrMaxLengthApplies() const { return IsSingleLineTextControl(false, mType); }
|
||||
|
||||
void FreeData();
|
||||
nsTextEditorState *GetEditorState() const;
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
/**
|
||||
* Manages the internal data storage across type changes.
|
||||
|
|
@ -1629,6 +1642,11 @@ protected:
|
|||
bool mNumberControlSpinnerSpinsUp : 1;
|
||||
bool mPickerRunning : 1;
|
||||
bool mSelectionCached : 1;
|
||||
/**
|
||||
* The value that was autofilled by the browser. Used to persist the autofill
|
||||
* highlight as long as the value matches, regardless of focus/blur.
|
||||
*/
|
||||
nsString mAutofilledValue;
|
||||
|
||||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
|
|
@ -1772,6 +1790,8 @@ private:
|
|||
nsCOMPtr<nsIFilePicker> mFilePicker;
|
||||
RefPtr<HTMLInputElement> mInput;
|
||||
};
|
||||
|
||||
void EnsureAutofillState();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -366,6 +366,46 @@ HTMLTextAreaElement::SetUserInput(const nsAString& aValue)
|
|||
return SetValueInternal(aValue, nsTextEditorState::eSetValue_BySetUserInput);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTextAreaElement::SetAutofilled(bool aAutofilled)
|
||||
{
|
||||
if (aAutofilled) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
GetValueInternal(mAutofilledValue, true); // Store the autofilled value
|
||||
} else {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, true);
|
||||
|
||||
// Only remove autofilled state if the value actually changed from autofilled value
|
||||
if (State().HasState(NS_EVENT_STATE_AUTOFILL) || !mAutofilledValue.IsEmpty()) {
|
||||
if (aWasInteractiveUserChange && mAutofilledValue != value) {
|
||||
RemoveStates(NS_EVENT_STATE_AUTOFILL);
|
||||
mAutofilledValue.Truncate();
|
||||
} else if (aWasInteractiveUserChange && mAutofilledValue == value) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the validity state
|
||||
bool validBefore = IsValid();
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
if (validBefore != IsValid() ||
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::SetValueChanged(bool aValueChanged)
|
||||
{
|
||||
|
|
@ -556,6 +596,19 @@ HTMLTextAreaElement::FireChangeEventIfNeeded()
|
|||
false);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLTextAreaElement::EnsureAutofillState()
|
||||
{
|
||||
nsAutoString value;
|
||||
GetValueInternal(value, true);
|
||||
if (!mAutofilledValue.IsEmpty() && mAutofilledValue == value) {
|
||||
if (!State().HasState(NS_EVENT_STATE_AUTOFILL)) {
|
||||
AddStates(NS_EVENT_STATE_AUTOFILL);
|
||||
UpdateState(true); // Force style system to re-evaluate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
||||
{
|
||||
|
|
@ -580,6 +633,9 @@ HTMLTextAreaElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
|
|||
}
|
||||
|
||||
UpdateState(true);
|
||||
|
||||
// Defensive: re-apply autofill state if value is still autofilled value
|
||||
EnsureAutofillState();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
|
@ -1186,6 +1242,10 @@ HTMLTextAreaElement::IntrinsicState() const
|
|||
{
|
||||
EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
|
||||
|
||||
if (!mAutofilledValue.IsEmpty()) {
|
||||
state |= NS_EVENT_STATE_AUTOFILL;
|
||||
}
|
||||
|
||||
if (HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
|
||||
state |= NS_EVENT_STATE_REQUIRED;
|
||||
} else {
|
||||
|
|
@ -1628,23 +1688,6 @@ HTMLTextAreaElement::InitializeKeyboardEventListeners()
|
|||
mState.InitializeKeyboardEventListeners();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(void)
|
||||
HTMLTextAreaElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
|
||||
{
|
||||
mLastValueChangeWasInteractive = aWasInteractiveUserChange;
|
||||
|
||||
// Update the validity state
|
||||
bool validBefore = IsValid();
|
||||
UpdateTooLongValidityState();
|
||||
UpdateTooShortValidityState();
|
||||
UpdateValueMissingValidityState();
|
||||
|
||||
if (validBefore != IsValid() ||
|
||||
HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
|
||||
UpdateState(aNotify);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(bool)
|
||||
HTMLTextAreaElement::HasCachedSelection()
|
||||
{
|
||||
|
|
@ -1660,11 +1703,33 @@ HTMLTextAreaElement::FieldSetDisabledChanged(bool aNotify)
|
|||
nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::BeginProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLTextAreaElement::EndProgrammaticValueSet() {
|
||||
nsTextEditorState* state = GetEditorState();
|
||||
if (state) {
|
||||
state->SettingValue(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLTextAreaElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return HTMLTextAreaElementBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsTextEditorState* HTMLTextAreaElement::GetEditorState() const {
|
||||
return const_cast<nsTextEditorState*>(&mState);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -69,6 +69,17 @@ public:
|
|||
return nsGenericHTMLElement::GetEditor(aEditor);
|
||||
}
|
||||
NS_IMETHOD SetUserInput(const nsAString& aInput) override;
|
||||
NS_IMETHOD BeginProgrammaticValueSet() override;
|
||||
NS_IMETHOD EndProgrammaticValueSet() override;
|
||||
|
||||
/**
|
||||
* Sets or clears the autofilled state of this textarea element.
|
||||
* This is used by the browser's autofill system to indicate when
|
||||
* a value has been automatically filled (e.g., from saved form data).
|
||||
*
|
||||
* @param aAutofilled Whether the element should be marked as autofilled
|
||||
*/
|
||||
void SetAutofilled(bool aAutofilled);
|
||||
|
||||
// nsIFormControl
|
||||
NS_IMETHOD_(uint32_t) GetType() const override { return NS_FORM_TEXTAREA; }
|
||||
|
|
@ -293,6 +304,7 @@ public:
|
|||
{
|
||||
return mState.GetEditor();
|
||||
}
|
||||
nsTextEditorState* GetEditorState() const;
|
||||
|
||||
protected:
|
||||
virtual ~HTMLTextAreaElement() {}
|
||||
|
|
@ -324,6 +336,7 @@ protected:
|
|||
void FireChangeEventIfNeeded();
|
||||
|
||||
nsString mFocusedValue;
|
||||
nsString mAutofilledValue;
|
||||
|
||||
/** The state of the text editor (selection controller and the editor) **/
|
||||
nsTextEditorState mState;
|
||||
|
|
@ -397,6 +410,7 @@ protected:
|
|||
private:
|
||||
static void MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
|
||||
nsRuleData* aData);
|
||||
void EnsureAutofillState();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
|||
|
|
@ -163,6 +163,7 @@ public:
|
|||
// or reconsider fixing bug 597525 to remove these.
|
||||
void EmptyValue() { if (mValue) mValue->Truncate(); }
|
||||
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
|
||||
void SettingValue(bool aValue) { mSettingValue = aValue; }
|
||||
|
||||
nsresult CreatePlaceholderNode();
|
||||
|
||||
|
|
@ -348,6 +349,7 @@ private:
|
|||
mutable bool mSelectionRestoreEagerInit; // Whether we're eager initing because of selection restore
|
||||
bool mPlaceholderVisibility;
|
||||
bool mIsCommittingComposition;
|
||||
bool mSettingValue;
|
||||
};
|
||||
|
||||
inline void
|
||||
|
|
|
|||
|
|
@ -1944,6 +1944,20 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
const long MOUSE_BUTTONS_5TH_BUTTON = 0x10;
|
||||
// Buttons are not specified, will be calculated from |aButton|.
|
||||
const long MOUSE_BUTTONS_NOT_SPECIFIED = -1;
|
||||
|
||||
/**
|
||||
* Add an EventState bit to an element (privileged only).
|
||||
* @param element The element to modify.
|
||||
* @param state The EventState bit (see EventStates.h, e.g. NS_EVENT_STATE_AUTOFILL).
|
||||
*/
|
||||
void addElementEventState(in nsIDOMElement element, in unsigned long long state);
|
||||
|
||||
/**
|
||||
* Remove an EventState bit from an element (privileged only).
|
||||
* @param element The element to modify.
|
||||
* @param state The EventState bit.
|
||||
*/
|
||||
void removeElementEventState(in nsIDOMElement element, in unsigned long long state);
|
||||
};
|
||||
|
||||
[scriptable, uuid(c694e359-7227-4392-a138-33c0cc1f15a6)]
|
||||
|
|
|
|||
|
|
@ -25,4 +25,10 @@ interface nsIDOMNSEditableElement : nsISupports
|
|||
// 'change' event for example will be dispatched when focusing out the
|
||||
// element.
|
||||
[noscript] void setUserInput(in DOMString input);
|
||||
/**
|
||||
* Call this before and after programmatically setting the value to prevent
|
||||
* OnValueChanged from treating it as a user edit.
|
||||
*/
|
||||
void beginProgrammaticValueSet();
|
||||
void endProgrammaticValueSet();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -200,6 +200,13 @@ partial interface HTMLInputElement {
|
|||
// for example will be dispatched when focusing out the element.
|
||||
[Func="IsChromeOrXBL", NeedsSubjectPrincipal]
|
||||
void setUserInput(DOMString input);
|
||||
|
||||
// Sets or clears the autofilled state of this input element.
|
||||
// This is used by the browser's autofill system to indicate when
|
||||
// a value has been automatically filled (e.g., from saved passwords
|
||||
// or form data).
|
||||
[ChromeOnly]
|
||||
void setAutofilled(boolean autofilled);
|
||||
};
|
||||
|
||||
partial interface HTMLInputElement {
|
||||
|
|
|
|||
|
|
@ -97,4 +97,10 @@ partial interface HTMLTextAreaElement {
|
|||
// element.
|
||||
[ChromeOnly]
|
||||
void setUserInput(DOMString input);
|
||||
|
||||
// Sets or clears the autofilled state of this textarea element.
|
||||
// This is used by the browser's autofill system to indicate when
|
||||
// a value has been automatically filled (e.g., from saved form data).
|
||||
[ChromeOnly]
|
||||
void setAutofilled(boolean autofilled);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -348,6 +348,41 @@ NS_HSL2RGB(float h, float s, float l)
|
|||
return NS_RGB(r, g, b);
|
||||
}
|
||||
|
||||
// RGB to HSL conversion function
|
||||
// The uint8_t RGB parameters are expected to be in the range 0-255
|
||||
// Returns HSL values in the range: H[0-1], S[0-1], L[0-1]
|
||||
void
|
||||
NS_RGB2HSL(uint8_t aR, uint8_t aG, uint8_t aB, float* aH, float* aS, float* aL)
|
||||
{
|
||||
float r = aR / 255.0f;
|
||||
float g = aG / 255.0f;
|
||||
float b = aB / 255.0f;
|
||||
|
||||
float max = std::max(r, std::max(g, b));
|
||||
float min = std::min(r, std::min(g, b));
|
||||
float h, s, l = (max + min) / 2.0f;
|
||||
|
||||
if (max == min) {
|
||||
h = s = 0.0f; // achromatic
|
||||
} else {
|
||||
float d = max - min;
|
||||
s = l > 0.5f ? d / (2.0f - max - min) : d / (max + min);
|
||||
|
||||
if (max == r) {
|
||||
h = (g - b) / d + (g < b ? 6.0f : 0.0f);
|
||||
} else if (max == g) {
|
||||
h = (b - r) / d + 2.0f;
|
||||
} else {
|
||||
h = (r - g) / d + 4.0f;
|
||||
}
|
||||
h /= 6.0f;
|
||||
}
|
||||
|
||||
*aH = h;
|
||||
*aS = s;
|
||||
*aL = l;
|
||||
}
|
||||
|
||||
const char*
|
||||
NS_RGBToColorName(nscolor aColor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -113,6 +113,11 @@ const char * const * NS_AllColorNames(size_t *aSizeArray);
|
|||
// the float parameters are all expected to be in the range 0-1
|
||||
nscolor NS_HSL2RGB(float h, float s, float l);
|
||||
|
||||
// function to convert from RGB color space to HSL color space
|
||||
// the uint8_t RGB parameters are expected to be in the range 0-255
|
||||
// the float HSL parameters will be set to values in the range 0-1
|
||||
void NS_RGB2HSL(uint8_t aR, uint8_t aG, uint8_t aB, float* aH, float* aS, float* aL);
|
||||
|
||||
// Return a color name for the given nscolor. If there is no color
|
||||
// name for it, returns null. If there are multiple possible color
|
||||
// names for the given color, the first one in nsColorNameList.h
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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___ */
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -2713,6 +2713,12 @@ pref("layout.css.resizeobserver.enabled", true);
|
|||
// Is support for cascade layers enabled?
|
||||
pref("layout.css.cascade-layers.enabled", true);
|
||||
|
||||
// Should rules in imported style sheets be added based on the order
|
||||
// of appearance of their respective @import rules in the parent
|
||||
// style sheet? Otherwise, they are added before rules preceding
|
||||
// @import are processed, which is problematic for cascade layers.
|
||||
pref("layout.css.load-imported-sheets-in-order", true);
|
||||
|
||||
// pref for which side vertical scrollbars should be on
|
||||
// 0 = end-side in UI direction
|
||||
// 1 = end-side in document/content direction
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* See the nsIFormAutofillContentService documentation for details.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
"use strict"
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||
|
||||
|
|
@ -29,6 +29,15 @@ function FormHandler(aForm, aWindow) {
|
|||
this.window = aWindow;
|
||||
|
||||
this.fieldDetails = [];
|
||||
|
||||
// Add a reset event listener to clear autofill state
|
||||
this.form.addEventListener("reset", () => {
|
||||
for (let element of this.form.elements) {
|
||||
if (typeof element.setAutofilled === "function") {
|
||||
element.setAutofilled(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
FormHandler.prototype = {
|
||||
|
|
@ -233,11 +242,14 @@ FormHandler.prototype = {
|
|||
f.addressType == field.addressType &&
|
||||
f.contactType == field.contactType &&
|
||||
f.fieldName == field.fieldName);
|
||||
|
||||
if (!fieldDetail) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fieldDetail.element.value = field.value;
|
||||
if (typeof fieldDetail.element.setAutofilled === 'function') {
|
||||
fieldDetail.element.setAutofilled(!!field.value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -1189,7 +1189,7 @@ var LoginManagerContent = {
|
|||
// Fill the form
|
||||
|
||||
if (usernameField) {
|
||||
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
|
||||
// Don't modify the username field if it's disabled or readOnly so we preserve its case.
|
||||
let disabledOrReadOnly = usernameField.disabled || usernameField.readOnly;
|
||||
|
||||
let userNameDiffers = selectedLogin.username != usernameField.value;
|
||||
|
|
@ -1202,6 +1202,10 @@ var LoginManagerContent = {
|
|||
if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) {
|
||||
usernameField.setUserInput(selectedLogin.username);
|
||||
}
|
||||
//Set autofilled state if value is present
|
||||
if (typeof usernameField.setAutofilled === "function" && usernameField.value) {
|
||||
usernameField.setAutofilled(true);
|
||||
}
|
||||
}
|
||||
|
||||
let doc = form.ownerDocument;
|
||||
|
|
@ -1216,6 +1220,10 @@ var LoginManagerContent = {
|
|||
};
|
||||
log("Saving autoFilledLogin", autoFilledLogin.guid, "for", form.rootElement);
|
||||
this.stateForDocument(doc).fillsByRootElement.set(form.rootElement, autoFilledLogin);
|
||||
// Set autofilled state if value is present
|
||||
if (typeof passwordField.setAutofilled === "function" && passwordField.value) {
|
||||
passwordField.setAutofilled(true);
|
||||
}
|
||||
}
|
||||
|
||||
log("_fillForm succeeded");
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "nsIFrame.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsFocusManager.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
|
@ -541,9 +542,24 @@ nsFormFillController::SetTextValue(const nsAString & aTextValue)
|
|||
{
|
||||
nsCOMPtr<nsIDOMNSEditableElement> editable = do_QueryInterface(mFocusedInput);
|
||||
if (editable) {
|
||||
editable->BeginProgrammaticValueSet();
|
||||
mSuppressOnInput = true;
|
||||
editable->SetUserInput(aTextValue);
|
||||
mSuppressOnInput = false;
|
||||
editable->EndProgrammaticValueSet();
|
||||
|
||||
if (mFocusedInput) {
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(mFocusedInput);
|
||||
if (content) {
|
||||
mozilla::dom::HTMLInputElement* htmlInput = mozilla::dom::HTMLInputElement::FromContentOrNull(content);
|
||||
if (htmlInput) {
|
||||
htmlInput->SetAutofilled(true);
|
||||
nsAutoString value;
|
||||
htmlInput->GetValue(value);
|
||||
htmlInput->SetAutofilledValue(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -1331,9 +1347,6 @@ nsFormFillController::StopControllingInput()
|
|||
nsresult rv;
|
||||
nsCOMPtr <nsIFormAutoComplete> formAutoComplete =
|
||||
do_GetService("@mozilla.org/satchel/form-autocomplete;1", &rv);
|
||||
if (formAutoComplete) {
|
||||
formAutoComplete->StopControllingInput(mFocusedInput);
|
||||
}
|
||||
|
||||
mFocusedInputNode = nullptr;
|
||||
mFocusedInput = nullptr;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue