mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-27 02:29:35 +00:00
parent
467573125f
commit
d22246efad
|
@ -173,6 +173,7 @@ static const char* kObservedPrefs[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
nsFocusManager::nsFocusManager()
|
nsFocusManager::nsFocusManager()
|
||||||
|
: mEventHandlingNeedsFlush(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
nsFocusManager::~nsFocusManager()
|
nsFocusManager::~nsFocusManager()
|
||||||
|
@ -1522,6 +1523,7 @@ nsFocusManager::CheckIfFocusable(nsIContent* aContent, uint32_t aFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that our frames are up to date
|
// Make sure that our frames are up to date
|
||||||
|
mEventHandlingNeedsFlush = false;
|
||||||
doc->FlushPendingNotifications(Flush_Layout);
|
doc->FlushPendingNotifications(Flush_Layout);
|
||||||
|
|
||||||
nsIPresShell *shell = doc->GetShell();
|
nsIPresShell *shell = doc->GetShell();
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#define nsFocusManager_h___
|
#define nsFocusManager_h___
|
||||||
|
|
||||||
#include "nsCycleCollectionParticipant.h"
|
#include "nsCycleCollectionParticipant.h"
|
||||||
|
#include "nsIContent.h"
|
||||||
#include "nsIDocument.h"
|
#include "nsIDocument.h"
|
||||||
#include "nsIFocusManager.h"
|
#include "nsIFocusManager.h"
|
||||||
#include "nsIObserver.h"
|
#include "nsIObserver.h"
|
||||||
|
@ -93,6 +94,29 @@ public:
|
||||||
return handlingDocument.forget();
|
return handlingDocument.forget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NeedsFlushBeforeEventHandling(nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (mFocusedContent == aContent) {
|
||||||
|
mEventHandlingNeedsFlush = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanSkipFocus(nsIContent* aContent)
|
||||||
|
{
|
||||||
|
return mFocusedContent == aContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlushBeforeEventHandlingIfNeeded(nsIContent* aContent)
|
||||||
|
{
|
||||||
|
if (mEventHandlingNeedsFlush) {
|
||||||
|
nsCOMPtr<nsIDocument> doc = aContent->GetComposedDoc();
|
||||||
|
if (doc) {
|
||||||
|
mEventHandlingNeedsFlush = false;
|
||||||
|
doc->FlushPendingNotifications(Flush_Layout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the caret with current mode (whether in caret browsing mode or not).
|
* Update the caret with current mode (whether in caret browsing mode or not).
|
||||||
*/
|
*/
|
||||||
|
@ -513,6 +537,10 @@ private:
|
||||||
// moving focus.
|
// moving focus.
|
||||||
nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
|
nsCOMPtr<nsIDocument> mMouseButtonEventHandlingDocument;
|
||||||
|
|
||||||
|
// If set to true, layout of the document of the event target should be
|
||||||
|
// flushed before handling focus depending events.
|
||||||
|
bool mEventHandlingNeedsFlush;
|
||||||
|
|
||||||
static bool sTestMode;
|
static bool sTestMode;
|
||||||
|
|
||||||
// the single focus manager
|
// the single focus manager
|
||||||
|
|
|
@ -1465,6 +1465,10 @@ HTMLInputElement::GetValueInternal(nsAString& aValue) const
|
||||||
bool
|
bool
|
||||||
HTMLInputElement::IsValueEmpty() const
|
HTMLInputElement::IsValueEmpty() const
|
||||||
{
|
{
|
||||||
|
if (GetValueMode() == VALUE_MODE_VALUE && IsSingleLineTextControl(false)) {
|
||||||
|
return !mInputData.mState->HasNonEmptyValue();
|
||||||
|
}
|
||||||
|
|
||||||
nsAutoString value;
|
nsAutoString value;
|
||||||
GetValueInternal(value);
|
GetValueInternal(value);
|
||||||
|
|
||||||
|
@ -4277,6 +4281,14 @@ HTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||||
void
|
void
|
||||||
HTMLInputElement::HandleTypeChange(uint8_t aNewType)
|
HTMLInputElement::HandleTypeChange(uint8_t aNewType)
|
||||||
{
|
{
|
||||||
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
|
if (fm) {
|
||||||
|
// Input element can represent very different kinds of UIs, and we may
|
||||||
|
// need to flush styling even when focusing the already focused input
|
||||||
|
// element.
|
||||||
|
fm->NeedsFlushBeforeEventHandling(this);
|
||||||
|
}
|
||||||
|
|
||||||
if (mType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
|
if (mType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
|
||||||
CancelRangeThumbDrag(false);
|
CancelRangeThumbDrag(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2668,8 +2668,11 @@ nsGenericHTMLElement::Blur(mozilla::ErrorResult& aError)
|
||||||
void
|
void
|
||||||
nsGenericHTMLElement::Focus(ErrorResult& aError)
|
nsGenericHTMLElement::Focus(ErrorResult& aError)
|
||||||
{
|
{
|
||||||
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
if (fm) {
|
if (fm) {
|
||||||
|
if (fm->CanSkipFocus(this))
|
||||||
|
fm->NeedsFlushBeforeEventHandling(this);
|
||||||
|
else
|
||||||
aError = fm->SetFocus(this, 0);
|
aError = fm->SetFocus(this, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2174,6 +2174,23 @@ nsTextEditorState::SetValue(const nsAString& aValue, uint32_t aFlags)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
nsTextEditorState::HasNonEmptyValue()
|
||||||
|
{
|
||||||
|
if (mEditor && mBoundFrame && mEditorInitialized &&
|
||||||
|
!mIsCommittingComposition) {
|
||||||
|
bool empty;
|
||||||
|
nsresult rv = mEditor->GetDocumentIsEmpty(&empty);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
return !empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsAutoString value;
|
||||||
|
GetValue(value, true);
|
||||||
|
return !value.IsEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsTextEditorState::InitializeKeyboardEventListeners()
|
nsTextEditorState::InitializeKeyboardEventListeners()
|
||||||
{
|
{
|
||||||
|
|
|
@ -158,6 +158,11 @@ public:
|
||||||
MOZ_WARN_UNUSED_RESULT bool SetValue(const nsAString& aValue,
|
MOZ_WARN_UNUSED_RESULT bool SetValue(const nsAString& aValue,
|
||||||
uint32_t aFlags);
|
uint32_t aFlags);
|
||||||
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
|
void GetValue(nsAString& aValue, bool aIgnoreWrap) const;
|
||||||
|
bool HasNonEmptyValue();
|
||||||
|
// The following methods are for textarea element to use whether default
|
||||||
|
// value or not.
|
||||||
|
// XXX We might have to add assertion when it is into editable,
|
||||||
|
// or reconsider fixing bug 597525 to remove these.
|
||||||
void EmptyValue() { if (mValue) mValue->Truncate(); }
|
void EmptyValue() { if (mValue) mValue->Truncate(); }
|
||||||
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
|
bool IsEmpty() const { return mValue ? mValue->IsEmpty() : true; }
|
||||||
|
|
||||||
|
|
|
@ -7815,6 +7815,13 @@ PresShell::HandleEventInternal(WidgetEvent* aEvent,
|
||||||
bool touchIsNew = false;
|
bool touchIsNew = false;
|
||||||
bool isHandlingUserInput = false;
|
bool isHandlingUserInput = false;
|
||||||
|
|
||||||
|
if (mCurrentEventContent && aEvent->IsTargetedAtFocusedWindow()) {
|
||||||
|
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||||
|
if (fm) {
|
||||||
|
fm->FlushBeforeEventHandlingIfNeeded(mCurrentEventContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// XXX How about IME events and input events for plugins?
|
// XXX How about IME events and input events for plugins?
|
||||||
if (aEvent->mFlags.mIsTrusted) {
|
if (aEvent->mFlags.mIsTrusted) {
|
||||||
switch (aEvent->mMessage) {
|
switch (aEvent->mMessage) {
|
||||||
|
|
|
@ -396,6 +396,7 @@ nsFrame::nsFrame(nsStyleContext* aContext)
|
||||||
MOZ_COUNT_CTOR(nsFrame);
|
MOZ_COUNT_CTOR(nsFrame);
|
||||||
|
|
||||||
mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
|
mState = NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY;
|
||||||
|
mMayHaveRoundedCorners = false;
|
||||||
mStyleContext = aContext;
|
mStyleContext = aContext;
|
||||||
mStyleContext->AddRef();
|
mStyleContext->AddRef();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -876,6 +877,7 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
||||||
NS_FRAME_SIMPLE_DISPLAYLIST);
|
NS_FRAME_SIMPLE_DISPLAYLIST);
|
||||||
*/
|
*/
|
||||||
RemoveStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
|
RemoveStateBits(NS_FRAME_SIMPLE_DISPLAYLIST);
|
||||||
|
mMayHaveRoundedCorners = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// MSVC fails with link error "one or more multiply defined symbols found",
|
// MSVC fails with link error "one or more multiply defined symbols found",
|
||||||
|
@ -1289,6 +1291,11 @@ nsIFrame::OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets)
|
||||||
nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
|
nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
|
||||||
Sides aSkipSides, nscoord aRadii[8]) const
|
Sides aSkipSides, nscoord aRadii[8]) const
|
||||||
{
|
{
|
||||||
|
if (!mMayHaveRoundedCorners) {
|
||||||
|
memset(aRadii, 0, sizeof(nscoord) * 8);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsThemed()) {
|
if (IsThemed()) {
|
||||||
// When we're themed, the native theme code draws the border and
|
// When we're themed, the native theme code draws the border and
|
||||||
// background, and therefore it doesn't make sense to tell other
|
// background, and therefore it doesn't make sense to tell other
|
||||||
|
@ -1302,9 +1309,12 @@ nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return ComputeBorderRadii(StyleBorder()->mBorderRadius,
|
|
||||||
|
const_cast<nsIFrame*>(this)->mMayHaveRoundedCorners =
|
||||||
|
ComputeBorderRadii(StyleBorder()->mBorderRadius,
|
||||||
aFrameSize, aBorderArea,
|
aFrameSize, aBorderArea,
|
||||||
aSkipSides, aRadii);
|
aSkipSides, aRadii);
|
||||||
|
return mMayHaveRoundedCorners;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -3152,6 +3152,8 @@ protected:
|
||||||
VisualDeltas mVisualDeltas;
|
VisualDeltas mVisualDeltas;
|
||||||
} mOverflow;
|
} mOverflow;
|
||||||
|
|
||||||
|
bool mMayHaveRoundedCorners : 1;
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
/**
|
/**
|
||||||
* Can we stop inside this frame when we're skipping non-rendered whitespace?
|
* Can we stop inside this frame when we're skipping non-rendered whitespace?
|
||||||
|
|
|
@ -196,10 +196,39 @@
|
||||||
|
|
||||||
<field name="_scrollTarget">null</field>
|
<field name="_scrollTarget">null</field>
|
||||||
|
|
||||||
|
<method name="_boundsWithoutFlushing">
|
||||||
|
<parameter name="element"/>
|
||||||
|
<body><![CDATA[
|
||||||
|
if (!("_DOMWindowUtils" in this)) {
|
||||||
|
try {
|
||||||
|
this._DOMWindowUtils =
|
||||||
|
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
|
||||||
|
.getInterface(Components.interfaces.nsIDOMWindowUtils);
|
||||||
|
} catch (e) {
|
||||||
|
// Can't access nsIDOMWindowUtils if we're unprivileged.
|
||||||
|
this._DOMWindowUtils = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._DOMWindowUtils ?
|
||||||
|
this._DOMWindowUtils.getBoundsWithoutFlushing(element) :
|
||||||
|
element.getBoundingClientRect();
|
||||||
|
]]></body>
|
||||||
|
</method>
|
||||||
|
|
||||||
<method name="_canScrollToElement">
|
<method name="_canScrollToElement">
|
||||||
<parameter name="element"/>
|
<parameter name="element"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
return window.getComputedStyle(element).display != "none";
|
if (element.hidden) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if the element is hidden via CSS without the hidden attribute.
|
||||||
|
// If we get only zeros for the client rect, this means the element
|
||||||
|
// is hidden. As a performance optimization, we don't flush layout
|
||||||
|
// here which means that on the fly changes aren't fully supported.
|
||||||
|
let rect = this._boundsWithoutFlushing(element);
|
||||||
|
return !!(rect.top || rect.left || rect.width || rect.height);
|
||||||
]]></body>
|
]]></body>
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
|
@ -458,29 +487,29 @@
|
||||||
</method>
|
</method>
|
||||||
|
|
||||||
<method name="_updateScrollButtonsDisabledState">
|
<method name="_updateScrollButtonsDisabledState">
|
||||||
|
<parameter name="aScrolling"/>
|
||||||
<body><![CDATA[
|
<body><![CDATA[
|
||||||
var scrolledToStart = false;
|
let scrolledToStart;
|
||||||
var scrolledToEnd = false;
|
let scrolledToEnd;
|
||||||
|
|
||||||
|
// Avoid flushing layout when not overflowing or when scrolling.
|
||||||
if (this.hasAttribute("notoverflowing")) {
|
if (this.hasAttribute("notoverflowing")) {
|
||||||
scrolledToStart = true;
|
scrolledToStart = true;
|
||||||
scrolledToEnd = true;
|
scrolledToEnd = true;
|
||||||
}
|
} else if (aScrolling) {
|
||||||
else if (this.scrollPosition == 0) {
|
scrolledToStart = false;
|
||||||
|
scrolledToEnd = false;
|
||||||
|
} else if (this.scrollPosition == 0) {
|
||||||
// In the RTL case, this means the _last_ element in the
|
// In the RTL case, this means the _last_ element in the
|
||||||
// scrollbox is visible
|
// scrollbox is visible
|
||||||
if (this._isRTLScrollbox)
|
scrolledToEnd = this._isRTLScrollbox;
|
||||||
scrolledToEnd = true;
|
scrolledToStart = !this._isRTLScrollbox;
|
||||||
else
|
|
||||||
scrolledToStart = true;
|
|
||||||
}
|
}
|
||||||
else if (this.scrollClientSize + this.scrollPosition == this.scrollSize) {
|
else if (this.scrollClientSize + this.scrollPosition == this.scrollSize) {
|
||||||
// In the RTL case, this means the _first_ element in the
|
// In the RTL case, this means the _first_ element in the
|
||||||
// scrollbox is visible
|
// scrollbox is visible
|
||||||
if (this._isRTLScrollbox)
|
scrolledToStart = this._isRTLScrollbox;
|
||||||
scrolledToStart = true;
|
scrolledToEnd = !this._isRTLScrollbox;
|
||||||
else
|
|
||||||
scrolledToEnd = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scrolledToEnd)
|
if (scrolledToEnd)
|
||||||
|
@ -600,8 +629,29 @@
|
||||||
this.setAttribute("notoverflowing", "true");
|
this.setAttribute("notoverflowing", "true");
|
||||||
}
|
}
|
||||||
]]></handler>
|
]]></handler>
|
||||||
|
<handler event="scroll"><![CDATA[
|
||||||
|
if (!this._delayedUpdateScrollButtonsTimer) {
|
||||||
|
// This is the beginning of a scrolling animation. We need to update
|
||||||
|
// scroll buttons now in case we were scrolled to the start or to the
|
||||||
|
// end before we started scrolling.
|
||||||
|
this._updateScrollButtonsDisabledState(true);
|
||||||
|
} else {
|
||||||
|
// We're in the middle of the scrolling animation. We'll restart the
|
||||||
|
// delayed update request so that we only update the scroll buttons
|
||||||
|
// a second time once we're done scrolling.
|
||||||
|
window.clearTimeout(this._delayedUpdateScrollButtonsTimer);
|
||||||
|
}
|
||||||
|
|
||||||
<handler event="scroll" action="this._updateScrollButtonsDisabledState()"/>
|
// Try to detect the end of the scrolling animation to update the
|
||||||
|
// scroll buttons again. To avoid false positives, this timeout needs
|
||||||
|
// to be big enough to account for intermediate frames that don't move
|
||||||
|
// the scroll position in case we're scrolling slowly.
|
||||||
|
this._delayedUpdateScrollButtonsTimer = setTimeout(() => {
|
||||||
|
// Scrolling animation has finished.
|
||||||
|
this._delayedUpdateScrollButtonsTimer = 0;
|
||||||
|
this._updateScrollButtonsDisabledState();
|
||||||
|
}, 500);
|
||||||
|
]]></handler>
|
||||||
</handlers>
|
</handlers>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user