зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1155493 - Part 1: Add CaretStateChangedEvent and corresponding utility function. r=roc, sr=smaug
--HG-- extra : source : 1e690405d3146521cb01cf4b44c92028049f237f
This commit is contained in:
Родитель
454c80f550
Коммит
c1b8ea5c2d
|
@ -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;
|
||||
};
|
|
@ -725,6 +725,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
|||
'CameraConfigurationEvent.webidl',
|
||||
'CameraFacesDetectedEvent.webidl',
|
||||
'CameraStateChangeEvent.webidl',
|
||||
'CaretStateChangedEvent.webidl',
|
||||
'CFStateChangeEvent.webidl',
|
||||
'CloseEvent.webidl',
|
||||
'CSSFontFaceLoadEvent.webidl',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче