Bug 1067728 - Part 5 - Dispatch updateposition after scroll end and reflow. r=roc, sr=smaug

Add a selection state "updateposition" and a field "visible" to indicate
that the current selection's boundingClientRect or visible is changed.
We dispatch this state after scrolling or reflowing is done.
This commit is contained in:
Ting-Yu Lin 2014-12-10 01:50:00 +01:00
parent 09c7f0faf5
commit f674a2ec9b
4 changed files with 46 additions and 5 deletions

View File

@ -657,6 +657,7 @@ BrowserElementChild.prototype = {
zoomFactor: zoomFactor,
states: e.states,
isCollapsed: (e.selectedText.length == 0),
visible: e.visible,
};
// Get correct geometry information if we have nested iframe.

View File

@ -12,10 +12,12 @@ enum SelectionState {
"selectall",
"collapsetostart",
"collapsetoend",
"blur"
"blur",
"updateposition"
};
dictionary SelectionStateChangedEventInit : EventInit {
boolean visible = true;
DOMString selectedText = "";
DOMRectReadOnly? boundingClientRect = null;
sequence<SelectionState> states = [];
@ -24,6 +26,7 @@ dictionary SelectionStateChangedEventInit : EventInit {
[Constructor(DOMString type, optional SelectionStateChangedEventInit eventInit),
ChromeOnly]
interface SelectionStateChangedEvent : Event {
readonly attribute boolean visible;
readonly attribute DOMString selectedText;
readonly attribute DOMRectReadOnly? boundingClientRect;
[Cached, Pure] readonly attribute sequence<SelectionState> states;

View File

@ -87,6 +87,7 @@ SelectionCarets::SelectionCarets(nsIPresShell* aPresShell)
, mAsyncPanZoomEnabled(false)
, mEndCaretVisible(false)
, mStartCaretVisible(false)
, mSelectionVisibleInScrollFrames(true)
, mVisible(false)
{
MOZ_ASSERT(NS_IsMainThread());
@ -488,6 +489,22 @@ SelectionCarets::UpdateSelectionCarets()
mPresShell->FlushPendingNotifications(Flush_Layout);
// If the selection is not visible, we should dispatch a event.
nsIFrame* commonAncestorFrame =
nsLayoutUtils::FindNearestCommonAncestorFrame(startFrame, endFrame);
nsRect selectionRectInRootFrame = GetSelectionBoundingRect(selection);
nsRect selectionRectInCommonAncestorFrame = selectionRectInRootFrame;
nsLayoutUtils::TransformRect(rootFrame, commonAncestorFrame,
selectionRectInCommonAncestorFrame);
mSelectionVisibleInScrollFrames =
nsLayoutUtils::IsRectVisibleInScrollFrames(commonAncestorFrame,
selectionRectInCommonAncestorFrame);
SELECTIONCARETS_LOG("Selection visibility %s",
(mSelectionVisibleInScrollFrames ? "shown" : "hidden"));
nsRect firstRectInStartFrame =
nsCaret::GetGeometryForFrame(startFrame, startOffset, nullptr);
nsRect lastRectInEndFrame =
@ -989,6 +1006,15 @@ SelectionCarets::GetSelectionBoundingRect(Selection* aSel)
return res;
}
void
SelectionCarets::DispatchSelectionStateChangedEvent(Selection* aSelection,
SelectionState aState)
{
dom::Sequence<SelectionState> state;
state.AppendElement(aState);
DispatchSelectionStateChangedEvent(aSelection, state);
}
void
SelectionCarets::DispatchSelectionStateChangedEvent(Selection* aSelection,
const Sequence<SelectionState>& aStates)
@ -1008,6 +1034,7 @@ SelectionCarets::DispatchSelectionStateChangedEvent(Selection* aSelection,
domRect->SetLayoutRect(rect);
init.mBoundingClientRect = domRect;
init.mVisible = mSelectionVisibleInScrollFrames;
aSelection->Stringify(init.mSelectedText);
}
@ -1026,10 +1053,7 @@ void
SelectionCarets::NotifyBlur()
{
SetVisibility(false);
dom::Sequence<SelectionState> state;
state.AppendElement(dom::SelectionState::Blur);
DispatchSelectionStateChangedEvent(nullptr, state);
DispatchSelectionStateChangedEvent(nullptr, SelectionState::Blur);
}
nsresult
@ -1088,8 +1112,13 @@ SelectionCarets::AsyncPanZoomStopped(const mozilla::CSSIntPoint aScrollPos)
SELECTIONCARETS_LOG("Update selection carets after APZ is stopped!");
UpdateSelectionCarets();
// SelectionStateChangedEvent should be dispatched before ScrollViewChangeEvent.
DispatchSelectionStateChangedEvent(GetSelection(),
SelectionState::Updateposition);
SELECTIONCARETS_LOG("Dispatch scroll stopped with position x=%d, y=%d",
aScrollPos.x, aScrollPos.y);
DispatchScrollViewChangeEvent(mPresShell, dom::ScrollState::Stopped, aScrollPos);
}
@ -1179,6 +1208,8 @@ SelectionCarets::FireScrollEnd(nsITimer* aTimer, void* aSelectionCarets)
SELECTIONCARETS_LOG_STATIC("Update selection carets!");
self->SetVisibility(true);
self->UpdateSelectionCarets();
self->DispatchSelectionStateChangedEvent(self->GetSelection(),
SelectionState::Updateposition);
}
NS_IMETHODIMP
@ -1187,6 +1218,9 @@ SelectionCarets::Reflow(DOMHighResTimeStamp aStart, DOMHighResTimeStamp aEnd)
if (mVisible) {
SELECTIONCARETS_LOG("Update selection carets after reflow!");
UpdateSelectionCarets();
DispatchSelectionStateChangedEvent(GetSelection(),
SelectionState::Updateposition);
}
return NS_OK;
}

View File

@ -203,6 +203,8 @@ private:
dom::Selection* GetSelection();
already_AddRefed<nsFrameSelection> GetFrameSelection();
nsIContent* GetFocusedContent();
void DispatchSelectionStateChangedEvent(dom::Selection* aSelection,
dom::SelectionState aState);
void DispatchSelectionStateChangedEvent(dom::Selection* aSelection,
const dom::Sequence<dom::SelectionState>& aStates);
nsRect GetSelectionBoundingRect(dom::Selection* aSel);
@ -246,6 +248,7 @@ private:
bool mEndCaretVisible;
bool mStartCaretVisible;
bool mSelectionVisibleInScrollFrames;
bool mVisible;
// Preference