зеркало из https://github.com/mozilla/gecko-dev.git
Bug 824965: Implement a method of getting correct CaretPosition from within anonymous content nodes. [r=ehsan]
This commit is contained in:
Родитель
0fa8775c2d
Коммит
db66a98bce
|
@ -97,6 +97,7 @@ class nsScriptObjectTracer;
|
|||
class nsStringHashKey;
|
||||
class nsTextFragment;
|
||||
class nsViewportInfo;
|
||||
class nsIFrame;
|
||||
|
||||
struct JSContext;
|
||||
struct JSPropertyDescriptor;
|
||||
|
@ -2115,6 +2116,21 @@ public:
|
|||
int32_t& aOutStartOffset,
|
||||
int32_t& aOutEndOffset);
|
||||
|
||||
/**
|
||||
* Takes a frame for anonymous content within a text control (<input> or
|
||||
* <textarea>), and returns an offset in the text content, adjusted for a
|
||||
* trailing <br> frame.
|
||||
*
|
||||
* @param aOffsetFrame Frame for the text content in which the offset
|
||||
* lies
|
||||
* @param aOffset Offset as calculated by GetContentOffsetsFromPoint
|
||||
* @param aOutOffset Output adjusted offset
|
||||
*
|
||||
* @see GetSelectionInTextControl for the original basis of this function.
|
||||
*/
|
||||
static int32_t GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame,
|
||||
int32_t aOffset);
|
||||
|
||||
static nsIEditor* GetHTMLEditor(nsPresContext* aPresContext);
|
||||
|
||||
/**
|
||||
|
|
|
@ -101,6 +101,7 @@
|
|||
#include "nsIFormControl.h"
|
||||
#include "nsIForm.h"
|
||||
#include "nsIFragmentContentSink.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "nsIIdleService.h"
|
||||
#include "nsIImageLoadingContent.h"
|
||||
|
@ -6750,6 +6751,40 @@ nsContentUtils::TraceWrapper(nsWrapperCache* aCache, TraceCallback aCallback,
|
|||
}
|
||||
}
|
||||
|
||||
// static
|
||||
int32_t
|
||||
nsContentUtils::GetAdjustedOffsetInTextControl(nsIFrame* aOffsetFrame,
|
||||
int32_t aOffset)
|
||||
{
|
||||
// The structure of the anonymous frames within a text control frame is
|
||||
// an optional block frame, followed by an optional br frame.
|
||||
|
||||
// If the offset frame has a child, then this frame is the block which
|
||||
// has the text frames (containing the content) as its children. This will
|
||||
// be the case if we click to the right of any of the text frames, or at the
|
||||
// bottom of the text area.
|
||||
nsIFrame* firstChild = aOffsetFrame->GetFirstPrincipalChild();
|
||||
if (firstChild) {
|
||||
// In this case, the passed-in offset is incorrect, and we want the length
|
||||
// of the entire content in the text control frame.
|
||||
return firstChild->GetContent()->Length();
|
||||
}
|
||||
|
||||
if (aOffsetFrame->GetPrevSibling() &&
|
||||
!aOffsetFrame->GetNextSibling()) {
|
||||
// In this case, we're actually within the last frame, which is a br
|
||||
// frame. Our offset should therefore be the length of the first child of
|
||||
// our parent.
|
||||
int32_t aOutOffset =
|
||||
aOffsetFrame->GetParent()->GetFirstPrincipalChild()->GetContent()->Length();
|
||||
return aOutOffset;
|
||||
}
|
||||
|
||||
// Otherwise, we're within one of the text frames, in which case our offset
|
||||
// has already been correctly calculated.
|
||||
return aOffset;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsContentUtils::GetSelectionInTextControl(Selection* aSelection,
|
||||
|
|
|
@ -202,6 +202,9 @@
|
|||
#include "nsDOMEvent.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsITextControlElement.h"
|
||||
#include "nsIDOMNSEditableElement.h"
|
||||
#include "nsIEditor.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -9318,7 +9321,10 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
|||
|
||||
nsCOMPtr<nsIContent> node = offsets.content;
|
||||
uint32_t offset = offsets.offset;
|
||||
if (node && node->IsInNativeAnonymousSubtree()) {
|
||||
nsCOMPtr<nsIContent> anonNode = node;
|
||||
bool nodeIsAnonymous = node && node->IsInNativeAnonymousSubtree();
|
||||
if (nodeIsAnonymous) {
|
||||
node = ptFrame->GetContent();
|
||||
nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
|
||||
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon);
|
||||
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
|
||||
|
@ -9326,6 +9332,7 @@ nsIDocument::CaretPositionFromPoint(float aX, float aY)
|
|||
if (textArea || (input &&
|
||||
NS_SUCCEEDED(input->MozIsTextField(false, &isText)) &&
|
||||
isText)) {
|
||||
offset = nsContentUtils::GetAdjustedOffsetInTextControl(ptFrame, offset);
|
||||
node = nonanon;
|
||||
} else {
|
||||
node = nullptr;
|
||||
|
|
|
@ -21,17 +21,31 @@
|
|||
border: 8px solid black;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
#dp {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 2px;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
background-color: orange;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function displayPoint(aX, aY) {
|
||||
document.getElementById('dp').style['left'] = aX + "px";
|
||||
document.getElementById('dp').style['top'] = aY + "px";
|
||||
}
|
||||
|
||||
function convertEmToPx(aEm) {
|
||||
// Assumes our base font size is 16px = 12pt = 1.0em.
|
||||
var pxPerEm = 16.0 / 1.0;
|
||||
return pxPerEm * aEm;
|
||||
}
|
||||
|
||||
function checkOffsetsFromPoint(aX, aY, aExpected) {
|
||||
function checkOffsetsFromPoint(aX, aY, aExpected, aElementName='no-name') {
|
||||
var cp = document.caretPositionFromPoint(aX, aY);
|
||||
ok(aExpected == cp.offset, 'expected offset at (' + aX + ', ' + aY + '): ' + aExpected + ', got: ' + cp.offset);
|
||||
ok(aExpected == cp.offset, 'expected offset at (' + aX + ', ' + aY + ') [' + aElementName + ']: ' + aExpected + ', got: ' + cp.offset);
|
||||
}
|
||||
|
||||
function doTesting() {
|
||||
|
@ -39,8 +53,8 @@
|
|||
var test1Rect = test1Element.getBoundingClientRect();
|
||||
|
||||
// Check the first and last characters of the basic div.
|
||||
checkOffsetsFromPoint(Math.round(test1Rect.left + 1), Math.round(test1Rect.top + 1), 0);
|
||||
checkOffsetsFromPoint(Math.round(test1Rect.left + test1Rect.width - 1), Math.round(test1Rect.top + 1), 13);
|
||||
checkOffsetsFromPoint(Math.round(test1Rect.left + 1), Math.round(test1Rect.top + 1), 0, 'test1');
|
||||
checkOffsetsFromPoint(Math.round(test1Rect.left + test1Rect.width - 1), Math.round(test1Rect.top + 1), 13, 'test1');
|
||||
|
||||
// Check a middle character in the second line of the div.
|
||||
// To do this, we calculate 7em in from the left of the bounding
|
||||
|
@ -49,20 +63,19 @@
|
|||
var pixelsLeft = convertEmToPx(7);
|
||||
var test2Element = document.getElementById("test2");
|
||||
var test2Rect = test2Element.getBoundingClientRect();
|
||||
checkOffsetsFromPoint(Math.round(test2Rect.left + pixelsLeft + 1), Math.round(test2Rect.top + 1), 7);
|
||||
checkOffsetsFromPoint(Math.round(test2Rect.left + pixelsLeft + 1), Math.round(test2Rect.top + 1), 7, 'test2');
|
||||
|
||||
// Check the first and last characters of the textarea.
|
||||
var test3Element = document.getElementById('test3');
|
||||
var test3Rect = test3Element.getBoundingClientRect();
|
||||
checkOffsetsFromPoint(test3Rect.left + 1, test3Rect.top + 1, 0);
|
||||
// xxxTODO: This test is disabled due to bug 824965.
|
||||
//checkOffsetsFromPoint(Math.round(test3Rect.left + test3Rect.width - 1), Math.round(test3Rect.top + 1), 0);
|
||||
checkOffsetsFromPoint(test3Rect.left + 5, test3Rect.top + 5, 0, 'test3');
|
||||
checkOffsetsFromPoint(Math.round(test3Rect.left + test3Rect.width - 15), Math.round(test3Rect.top + 5), 3, 'test3');
|
||||
|
||||
// Check the first and last characters of the input.
|
||||
var test4Element = document.getElementById('test4');
|
||||
var test4Rect = test4Element.getBoundingClientRect();
|
||||
checkOffsetsFromPoint(test4Rect.left + 1, test4Rect.top + 1, 0);
|
||||
checkOffsetsFromPoint(Math.round(test4Rect.left + convertEmToPx(3)), Math.round(test4Rect.top + 10), 3);
|
||||
checkOffsetsFromPoint(test4Rect.left + 5, test4Rect.top + 5, 0, 'test4');
|
||||
checkOffsetsFromPoint(Math.round(test4Rect.left + test4Rect.width - 10), Math.round(test4Rect.top + 10), 6, 'test4');
|
||||
|
||||
// Check to make sure that x or y outside the viewport returns null.
|
||||
var nullCp1 = document.caretPositionFromPoint(-10, 0);
|
||||
|
@ -82,9 +95,10 @@
|
|||
</script>
|
||||
</head>
|
||||
<body onload="doTesting();">
|
||||
<div id="dp"></div>
|
||||
<div id="a" contenteditable><span id="test1">abc, abc, abc</span><br>
|
||||
<span id="test2" style="color: blue;">abc, abc, abc</span><br>
|
||||
<textarea id="test3">abc</textarea><input id="test4" value="abc"><br><br>
|
||||
<textarea id="test3">abc</textarea><input id="test4" value="abcdef"><br><br>
|
||||
<marquee>marquee</marquee>
|
||||
</div>
|
||||
</body>
|
||||
|
|
Загрузка…
Ссылка в новой задаче