Bug 654352: Implement (blassey) and fix (jwir3) document.caretPositionFromPoint so that it utilizes frame-relative coordinates to get caret position. (original: [r=smaug,roc]) (fixes: [r=blassey,Ms2ger])

This commit is contained in:
Scott Johnson 2012-12-21 16:36:31 -06:00
parent 778b4c1b2b
commit b39f9fb583
11 changed files with 312 additions and 2 deletions

View File

@ -74,6 +74,7 @@ CPPSRCS = \
nsDOMAttribute.cpp \
nsDOMAttributeMap.cpp \
nsDOMBlobBuilder.cpp \
nsDOMCaretPosition.cpp \
nsDOMDocumentType.cpp \
nsDOMFile.cpp \
nsDOMFileReader.cpp \

View File

@ -0,0 +1,40 @@
/* 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/. */
#include "nsDOMCaretPosition.h"
#include "mozilla/dom/CaretPositionBinding.h"
#include "nsContentUtils.h"
nsDOMCaretPosition::nsDOMCaretPosition(nsINode* aNode, uint32_t aOffset)
: mOffset(aOffset), mOffsetNode(aNode)
{
SetIsDOMBinding();
}
nsDOMCaretPosition::~nsDOMCaretPosition()
{
}
nsINode* nsDOMCaretPosition::GetOffsetNode() const
{
return mOffsetNode;
}
JSObject*
nsDOMCaretPosition::WrapObject(JSContext *aCx, JSObject *aScope,
bool *aTried)
{
return mozilla::dom::CaretPositionBinding::Wrap(aCx, aScope, this, aTried);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(nsDOMCaretPosition, mOffsetNode)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMCaretPosition)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMCaretPosition)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMCaretPosition)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

View File

@ -0,0 +1,63 @@
/* 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/. */
#ifndef nsDOMCaretPosition_h
#define nsDOMCaretPosition_h
#include "nsCycleCollectionParticipant.h"
#include "nsCOMPtr.h"
#include "nsINode.h"
#include "nsWrapperCache.h"
/**
* Implementation of a DOM Caret Position, which is a node and offset within
* that node, in the DOM tree.
*
* http://www.w3.org/TR/cssom-view/#dom-documentview-caretrangefrompoint
*
* @see Document::mozCaretPositionFromPoint(float x, float y)
*/
class nsDOMCaretPosition : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsDOMCaretPosition)
nsDOMCaretPosition(nsINode* aNode, uint32_t aOffset);
/**
* Retrieve the offset (character position within the DOM node) of the
* CaretPosition.
*
* @returns The offset within the DOM node.
*/
uint32_t Offset() const { return mOffset; }
/**
* Retrieve the DOM node with which this CaretPosition was established.
* Normally, this will be created from a point, so it will be the DOM
* node that lies at the point specified.
*
* @returns The DOM node of the CaretPosition.
*
* @see Document::mozCaretPositionFromPoint(float x, float y)
*/
nsINode* GetOffsetNode() const;
nsISupports* GetParentObject() const
{
return GetOffsetNode();
}
virtual JSObject* WrapObject(JSContext *aCx, JSObject *aScope, bool *aTried)
MOZ_OVERRIDE MOZ_FINAL;
protected:
virtual ~nsDOMCaretPosition();
uint32_t mOffset;
nsCOMPtr<nsINode> mOffsetNode;
};
#endif

View File

@ -181,6 +181,10 @@
#include "nsSandboxFlags.h"
#include "nsIAppsService.h"
#include "nsFrame.h"
#include "nsDOMCaretPosition.h"
#include "nsIDOMHTMLTextAreaElement.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -8650,6 +8654,64 @@ ResetFullScreen(nsIDocument* aDocument, void* aData)
return true;
}
NS_IMETHODIMP
nsDocument::MozCaretPositionFromPoint(float aX, float aY, nsISupports** aCaretPos)
{
NS_ENSURE_ARG_POINTER(aCaretPos);
*aCaretPos = nullptr;
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
nsPoint pt(x, y);
nsIPresShell *ps = GetShell();
if (!ps) {
return NS_OK;
}
nsIFrame *rootFrame = ps->GetRootFrame();
// XUL docs, unlike HTML, have no frame tree until everything's done loading
if (!rootFrame) {
return NS_OK; // return null to premature XUL callers as a reminder to wait
}
nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, true,
false);
if (!ptFrame) {
return NS_OK;
}
// GetContentOffsetsFromPoint requires frame-relative coordinates, so we need
// to adjust to frame-relative coordinates before we can perform this call.
// It should also not take into account the padding of the frame.
nsPoint adjustedPoint = pt - ptFrame->GetOffsetTo(rootFrame);
nsFrame::ContentOffsets offsets =
ptFrame->GetContentOffsetsFromPoint(adjustedPoint);
nsCOMPtr<nsIContent> node = offsets.content;
uint32_t offset = offsets.offset;
if (node && node->IsInNativeAnonymousSubtree()) {
nsIContent* nonanon = node->FindFirstNonChromeOnlyAccessContent();
nsCOMPtr<nsIDOMHTMLInputElement> input = do_QueryInterface(nonanon);
nsCOMPtr<nsIDOMHTMLTextAreaElement> textArea = do_QueryInterface(nonanon);
bool isText;
if (textArea || (input &&
NS_SUCCEEDED(input->MozIsTextField(false, &isText)) &&
isText)) {
node = nonanon;
} else {
node = nullptr;
offset = 0;
}
}
*aCaretPos = new nsDOMCaretPosition(node, offset);
NS_ADDREF(*aCaretPos);
return NS_OK;
}
/* static */
void
nsDocument::ExitFullScreen()

View File

@ -503,6 +503,8 @@ MOCHITEST_FILES_B = \
file_html_in_xhr3.html \
file_html_in_xhr.sjs \
test_bug647518.html \
test_bug654352.html \
test_bug654352-2.html \
test_bug664916.html \
test_bug666604.html \
test_bug675121.html \

View File

@ -0,0 +1,64 @@
<!doctype html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=654352
-->
<head>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<title>Test for Bug 654352</title>
<style>
#a {
padding: 10px;
border: 8px solid black;
width: 600px;
}
</style>
<script>
function checkOffsetsFromPoint(aX, aY, aExpected) {
var cp = document.mozCaretPositionFromPoint(aX, aY);
ok(aExpected == cp.offset, 'expected offset at (' + aX + ', ' + aY + '): ' + aExpected + ', got: ' + cp.offset);
}
function doTesting() {
// Tests at the beginning of the lines in the div
checkOffsetsFromPoint(27, 35, 0);
checkOffsetsFromPoint(25, 49, 1);
// Test within the lines in the div
checkOffsetsFromPoint(47, 57, 3);
checkOffsetsFromPoint(115, 35, 11);
/*
* These next two are questionably incorrect, as they both occur
* at the end of the two lines within the div. BUT, the
* new code matches the old code (focusOffset) for these,
* so it seems correct...
*/
checkOffsetsFromPoint(143, 34, 1);
checkOffsetsFromPoint(145, 51, 3);
// Tests within the text area and input
checkOffsetsFromPoint(45, 77, 2);
checkOffsetsFromPoint(204, 106, 2);
// Tests within the marquee
checkOffsetsFromPoint(44, 148, 1);
checkOffsetsFromPoint(103, 144, 7);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
</script>
</head>
<body onload="doTesting();">
<div id="a" contenteditable>abc, abc, abc<br>
abc, abc, abc<br>
<textarea>abc</textarea><input value="abc"><br><br>
<marquee>marquee</marquee>
</div>
</body>
</html>

View File

@ -0,0 +1,50 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=654352
-->
<head>
<title>Test for Bug 654352</title>
<script type="application/javascript" src="/MochiKit/packed.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=654352">Mozilla Bug 654352</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 654352 **/
SimpleTest.waitForExplicitFinish();
function afterLoad() {
var testpre = document.getElementById("testpre");
var rect1 = testpre.getBoundingClientRect();
dump(rect1 + "\n");
var caret1 = document.mozCaretPositionFromPoint(rect1.left + 30, rect1.top + 10);
ok(caret1.offsetNode == testpre.firstChild, "node in CaretPosition not correct (" + caret1.offsetNode + " == " + testpre.firstChild + ")")
ok(caret1.offset == 4, "offset in CaretPosition not correct (" + caret1.offset + "== 4)")
var testinput = document.getElementById("testinput");
var rect2 = testinput.getBoundingClientRect();
dump(rect2.top +", " + rect2.left + "\n");
var caret2 = document.mozCaretPositionFromPoint( rect2.left + 30, rect2.top + 10);
ok(caret2.offsetNode == testinput, "node in CaretPosition not correct (" + caret2.offsetNode + " == " + testinput + ")")
ok(caret2.offset == 4, "offset in CaretPosition not correct (" + caret2.offset + "== 4)")
SimpleTest.finish();
};
addLoadEvent(afterLoad);
</script>
</pre>
<span id="testdiv">
<pre id="testpre">test text</pre>
</span>
<br>
<br>
</div>
<input id="testinput" type="text" value="test text"></input>
</div>
</body>
</html>

View File

@ -180,6 +180,10 @@ DOMInterfaces = {
'skipGen': True
}],
'CaretPosition' : {
'nativeType': 'nsDOMCaretPosition',
},
'DOMParser': {
'nativeType': 'nsDOMParser',
},

View File

@ -27,7 +27,7 @@ interface nsIDOMLocation;
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
[scriptable, uuid(6f3aac2e-ae11-487a-9eb0-0e12c66b3b21)]
[scriptable, uuid(d19897dc-948a-42e7-8ac6-d8a0bd141b85)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;
@ -330,7 +330,7 @@ interface nsIDOMDocument : nsIDOMNode
*/
void mozSetImageElement(in DOMString aImageElementId,
in nsIDOMElement aImageElement);
/**
* Element which is currently the full-screen element as per the DOM
* full-screen api.
@ -372,6 +372,17 @@ interface nsIDOMDocument : nsIDOMNode
*/
readonly attribute nsIDOMElement mozPointerLockElement;
/**
* Retrieve the location of the caret position (DOM node and character
* offset within that node), given a point.
*
* @param x Horizontal point at which to determine the caret position, in
* page coordinates.
* @param y Vertical point at which to determine the caret position, in
* page coordinates.
*/
nsISupports /* CaretPosition */ mozCaretPositionFromPoint(in float x, in float y);
/**
* Exit pointer is lock if locked, as per the DOM pointer lock api.
*

View File

@ -0,0 +1,12 @@
/* 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/. */
interface CaretPosition {
/**
* The offsetNode could potentially be null due to anonymous content.
*/
readonly attribute Node? offsetNode;
readonly attribute unsigned long offset;
};

View File

@ -26,6 +26,7 @@ webidl_files = \
CSSValue.webidl \
CSSValueList.webidl \
DelayNode.webidl \
CaretPosition.webidl \
DOMImplementation.webidl \
DOMParser.webidl \
DOMSettableTokenList.webidl \