Bug 1155493 - Part 1: Add CaretStateChangedEvent and corresponding utility function. r=roc, sr=smaug

This commit is contained in:
Morris Tseng 2015-05-19 20:59:00 -04:00
parent 9b8cccf31b
commit bb1c4a8f28
4 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,32 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
enum CaretChangedReason {
"visibilitychange",
"updateposition",
"longpressonemptycontent",
"taponcaret",
"presscaret",
"releasecaret"
};
dictionary CaretStateChangedEventInit : EventInit {
boolean collapsed = true;
DOMRectReadOnly? boundingClientRect = null;
CaretChangedReason reason = "visibilitychange";
boolean caretVisible = false;
boolean selectionVisible = false;
};
[Constructor(DOMString type, optional CaretStateChangedEventInit eventInit),
ChromeOnly]
interface CaretStateChangedEvent : Event {
readonly attribute boolean collapsed;
readonly attribute DOMRectReadOnly? boundingClientRect;
readonly attribute CaretChangedReason reason;
readonly attribute boolean caretVisible;
readonly attribute boolean selectionVisible;
};

View File

@ -727,6 +727,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'CameraConfigurationEvent.webidl',
'CameraFacesDetectedEvent.webidl',
'CameraStateChangeEvent.webidl',
'CaretStateChangedEvent.webidl',
'CFStateChangeEvent.webidl',
'CloseEvent.webidl',
'CSSFontFaceLoadEvent.webidl',

View File

@ -866,4 +866,75 @@ AccessibleCaretManager::CancelCaretTimeoutTimer()
}
}
void
AccessibleCaretManager::DispatchCaretStateChangedEvent(CaretChangedReason aReason) const
{
MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
// Holding PresShell to prevent AccessibleCaretManager to be destroyed.
nsCOMPtr<nsIPresShell> presShell = mPresShell;
// XXX: Do we need to flush layout?
presShell->FlushPendingNotifications(Flush_Layout);
if (presShell->IsDestroying()) {
return;
}
Selection* sel = GetSelection();
if (!sel) {
return;
}
nsIDocument* doc = mPresShell->GetDocument();
MOZ_ASSERT(doc);
CaretStateChangedEventInit init;
init.mBubbles = true;
const nsRange* range = sel->GetAnchorFocusRange();
nsINode* commonAncestorNode = nullptr;
if (range) {
commonAncestorNode = range->GetCommonAncestor();
}
if (!commonAncestorNode) {
commonAncestorNode = sel->GetFrameSelection()->GetAncestorLimiter();
}
nsRefPtr<DOMRect> domRect = new DOMRect(ToSupports(doc));
nsRect rect = nsContentUtils::GetSelectionBoundingRect(sel);
nsIFrame* commonAncestorFrame = nullptr;
nsIFrame* rootFrame = mPresShell->GetRootFrame();
if (commonAncestorNode && commonAncestorNode->IsContent()) {
commonAncestorFrame = commonAncestorNode->AsContent()->GetPrimaryFrame();
}
if (commonAncestorFrame && rootFrame) {
nsLayoutUtils::TransformRect(rootFrame, commonAncestorFrame, rect);
nsRect clampedRect = nsLayoutUtils::ClampRectToScrollFrames(commonAncestorFrame,
rect);
nsLayoutUtils::TransformRect(commonAncestorFrame, rootFrame, clampedRect);
domRect->SetLayoutRect(clampedRect);
init.mSelectionVisible = !clampedRect.IsEmpty();
init.mBoundingClientRect = domRect;
} else {
domRect->SetLayoutRect(rect);
init.mSelectionVisible = true;
}
init.mBoundingClientRect = domRect;
init.mReason = aReason;
init.mCollapsed = sel->IsCollapsed();
init.mCaretVisible = mFirstCaret->IsLogicallyVisible() ||
mSecondCaret->IsLogicallyVisible();
nsRefPtr<CaretStateChangedEvent> event =
CaretStateChangedEvent::Constructor(doc, NS_LITERAL_STRING("mozcaretstatechanged"), init);
event->SetTrusted(true);
event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
bool ret;
doc->DispatchEvent(event, &ret);
}
} // namespace mozilla

View File

@ -13,6 +13,7 @@
#include "nsISelectionListener.h"
#include "nsRefPtr.h"
#include "nsWeakReference.h"
#include "mozilla/dom/CaretStateChangedEvent.h"
#include "mozilla/EventForwards.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
@ -132,6 +133,10 @@ protected:
already_AddRefed<nsFrameSelection> GetFrameSelection() const;
nsIContent* GetFocusedContent() const;
// This function will call FlushPendingNotifications. So caller must ensure
// everything exists after calling this method.
void DispatchCaretStateChangedEvent(dom::CaretChangedReason aReason) const;
// If we're dragging the first caret, we do not want to drag it over the
// previous character of the second caret. Same as the second caret. So we
// check if content offset exceeds the previous/next character of second/first