mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-12 21:05:36 +00:00
Bug 783531 - Implement a 'select word at point' text selection routine in nsIDOMWindowUtils. r=roc
This commit is contained in:
parent
22c79f9cc8
commit
bf296876b6
@ -19,6 +19,7 @@
|
||||
#include "nsDOMTouchEvent.h"
|
||||
#include "nsIDOMTouchEvent.h"
|
||||
#include "nsObjectLoadingContent.h"
|
||||
#include "nsFrame.h"
|
||||
|
||||
#include "nsIScrollableFrame.h"
|
||||
|
||||
@ -2809,3 +2810,76 @@ nsDOMWindowUtils::ExitFullscreen()
|
||||
nsIDocument::ExitFullScreen(/* async = */ false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::SelectAtPoint(float aX, float aY, PRUint32 aSelectBehavior,
|
||||
bool *_retval)
|
||||
{
|
||||
*_retval = false;
|
||||
if (!IsUniversalXPConnectCapable()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
nsSelectionAmount amount;
|
||||
switch (aSelectBehavior) {
|
||||
case nsIDOMWindowUtils::SELECT_CHARACTER:
|
||||
amount = eSelectCharacter;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_CLUSTER:
|
||||
amount = eSelectCluster;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_WORD:
|
||||
amount = eSelectWord;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_LINE:
|
||||
amount = eSelectLine;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_BEGINLINE:
|
||||
amount = eSelectBeginLine;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_ENDLINE:
|
||||
amount = eSelectEndLine;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_PARAGRAPH:
|
||||
amount = eSelectParagraph;
|
||||
break;
|
||||
case nsIDOMWindowUtils::SELECT_WORDNOSPACE:
|
||||
amount = eSelectWordNoSpace;
|
||||
break;
|
||||
}
|
||||
|
||||
nsIPresShell* presShell = GetPresShell();
|
||||
if (!presShell) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// The root frame for this content window
|
||||
nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame();
|
||||
if (!rootFrame) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Get the target frame at the client coordinates passed to us
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
nsIntPoint pt(aX, aY);
|
||||
nsPoint ptInRoot =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, rootFrame);
|
||||
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
|
||||
// This can happen if the page hasn't loaded yet or if the point
|
||||
// is outside the frame.
|
||||
if (!targetFrame) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// Convert point to coordinates relative to the target frame, which is
|
||||
// what targetFrame's SelectByTypeAtPoint expects.
|
||||
nsPoint relPoint =
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(widget, pt, targetFrame);
|
||||
|
||||
nsresult rv =
|
||||
static_cast<nsFrame*>(targetFrame)->
|
||||
SelectByTypeAtPoint(GetPresContext(), relPoint, amount, amount,
|
||||
nsFrame::SELECT_ACCUMULATE);
|
||||
*_retval = !NS_FAILED(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ interface nsIFile;
|
||||
interface nsIDOMTouch;
|
||||
interface nsIDOMClientRect;
|
||||
|
||||
[scriptable, uuid(f7222baa-7c4b-4079-a9e0-db13cf797f58)]
|
||||
[scriptable, uuid(8A7DA5AF-26FD-4449-8887-9BEADC938B0A)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
@ -921,6 +921,33 @@ interface nsIDOMWindowUtils : nsISupports {
|
||||
in unsigned long aLength,
|
||||
in boolean aReverse);
|
||||
|
||||
/* Selection behaviors - mirror nsIFrame's nsSelectionAmount constants */
|
||||
const unsigned long SELECT_CHARACTER = 0;
|
||||
const unsigned long SELECT_CLUSTER = 1;
|
||||
const unsigned long SELECT_WORD = 2;
|
||||
const unsigned long SELECT_LINE = 3;
|
||||
const unsigned long SELECT_BEGINLINE = 4;
|
||||
const unsigned long SELECT_ENDLINE = 5;
|
||||
const unsigned long SELECT_PARAGRAPH = 6;
|
||||
const unsigned long SELECT_WORDNOSPACE = 7;
|
||||
|
||||
/**
|
||||
* Select content at a client point based on a selection behavior if the
|
||||
* underlying content is selectable. Selection will accumulate with any
|
||||
* existing selection, callers should clear selection prior if needed.
|
||||
* May fire selection changed events. Calls nsFrame's SelectByTypeAtPoint.
|
||||
*
|
||||
* @param aX, aY The selection point in client coordinates.
|
||||
* @param aSelectType The selection behavior requested.
|
||||
* @return True if a selection occured, false otherwise.
|
||||
* @throw NS_ERROR_DOM_SECURITY_ERR, NS_ERROR_UNEXPECTED for utils
|
||||
* issues, and NS_ERROR_INVALID_ARG for coordinates that are outside
|
||||
* this window.
|
||||
*/
|
||||
boolean selectAtPoint(in float aX,
|
||||
in float aY,
|
||||
in unsigned long aSelectBehavior);
|
||||
|
||||
/**
|
||||
* Perform the equivalent of:
|
||||
* window.getComputedStyle(aElement, aPseudoElement).
|
||||
|
@ -46,6 +46,8 @@ MOCHITEST_CHROME_FILES = \
|
||||
window_callback_wrapping.xul \
|
||||
test_sandbox_postMessage.html \
|
||||
test_sandbox_bindings.xul \
|
||||
test_selectAtPoint.html \
|
||||
selectAtPoint.html \
|
||||
$(NULL)
|
||||
|
||||
ifeq (WINNT,$(OS_ARCH))
|
||||
|
271
dom/tests/mochitest/chrome/selectAtPoint.html
Normal file
271
dom/tests/mochitest/chrome/selectAtPoint.html
Normal file
@ -0,0 +1,271 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>nsIDOMWindowUtils::selectAtPoint test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
let SimpleTest = window.opener.SimpleTest;
|
||||
let Ci = Components.interfaces;
|
||||
|
||||
function ok() { window.opener.ok.apply(window.opener, arguments); }
|
||||
function done() { window.opener.done.apply(window.opener, arguments); }
|
||||
|
||||
function dumpLn() {
|
||||
for (let idx = 0; idx < arguments.length; idx++)
|
||||
dump(arguments[idx] + " ");
|
||||
dump("\n");
|
||||
}
|
||||
|
||||
function getCharacterDims() {
|
||||
let span = document.getElementById("measure");
|
||||
let rect = span.getBoundingClientRect();
|
||||
return { width: rect.right - rect.left,
|
||||
height: rect.bottom - rect.top };
|
||||
}
|
||||
|
||||
function setStart(aDWU, aX, aY, aSelectType)
|
||||
{
|
||||
// Clear any existing selection
|
||||
let selection = document.getSelection();
|
||||
selection.removeAllRanges();
|
||||
|
||||
// Select text
|
||||
let result = aDWU.selectAtPoint(aX, aY, aSelectType);
|
||||
ok(result == true, "selectAtPoint secceeded?");
|
||||
}
|
||||
|
||||
function setEnd(aDWU, aX, aY, aSelectType)
|
||||
{
|
||||
// Select text
|
||||
let result = aDWU.selectAtPoint(aX, aY, aSelectType);
|
||||
ok(result == true, "selectAtPoint secceeded?");
|
||||
}
|
||||
|
||||
function setSingle(aDWU, aX, aY, aSelectType, aSelectTypeStr, aExpectedSelectionText) {
|
||||
// Clear any existing selection
|
||||
let selection = document.getSelection();
|
||||
selection.removeAllRanges();
|
||||
|
||||
// Select text
|
||||
let result = aDWU.selectAtPoint(aX, aY, aSelectType);
|
||||
ok(result == true, "selectAtPoint secceeded?");
|
||||
}
|
||||
|
||||
function checkSelection(aDoc, aSelectTypeStr, aExpectedSelectionText) {
|
||||
// Retrieve text selected
|
||||
let selection = aDoc.getSelection();
|
||||
let text = selection.toString();
|
||||
|
||||
// Test
|
||||
let result = (text == aExpectedSelectionText);
|
||||
ok(result, aSelectTypeStr + " selection text matches?");
|
||||
if (!result) {
|
||||
dumpLn(aSelectTypeStr + " selection text:", "[" + text + "] expected:[" + aExpectedSelectionText + "]" );
|
||||
}
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
let os = Components.classes["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime).OS;
|
||||
let isLinux = (os == "Linux");
|
||||
let isMac = (os == "Darwin");
|
||||
let isWindows = (os == "WINNT");
|
||||
|
||||
if (!isLinux && !isMac && !isWindows) {
|
||||
done();
|
||||
return;
|
||||
}
|
||||
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
// Trick to get character spacing - get the bounds around a
|
||||
// single character trapped in a div.
|
||||
let charDims = getCharacterDims();
|
||||
// dumpLn("character dims:", charDims.width, charDims.height);
|
||||
|
||||
//
|
||||
// Root frame selection
|
||||
//
|
||||
|
||||
// First div in the main page
|
||||
|
||||
let div = document.getElementById("div1");
|
||||
let rect = div.getBoundingClientRect();
|
||||
|
||||
// Centered on the first character in the sentence div
|
||||
let targetPoint = { xPos: rect.left + (charDims.width / 2),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
|
||||
setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE);
|
||||
checkSelection(document, "SELECT_WORDNOSPACE", "ttestselection1");
|
||||
setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORD);
|
||||
if (isLinux || isMac) {
|
||||
checkSelection(document, "SELECT_WORD", "ttestselection1");
|
||||
} else if (isWindows) {
|
||||
checkSelection(document, "SELECT_WORD", "ttestselection1 ");
|
||||
}
|
||||
setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH);
|
||||
checkSelection(document, "SELECT_PARAGRAPH", "ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at.");
|
||||
|
||||
// Centered on the second character in the sentence div
|
||||
let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
|
||||
checkSelection(document, "SELECT_CHARACTER", "te");
|
||||
setSingle(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CLUSTER);
|
||||
checkSelection(document, "SELECT_CLUSTER", "te");
|
||||
|
||||
// Separate character blocks in a word 't(te)s(ts)election1'
|
||||
let targetPoint = { xPos: rect.left + (charDims.width + (charDims.width / 2)),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setStart(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
|
||||
let targetPoint = { xPos: rect.left + ((charDims.width * 4) + (charDims.width / 2)),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setEnd(dwu, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_CHARACTER);
|
||||
if (isLinux || isMac) {
|
||||
// XXX I think this is a bug, the right hand selection is 4.5 characters over with a
|
||||
// monspaced font. what we want: t(te)s(ts)election1 what we get: t(te)st(se)lection1
|
||||
checkSelection(document, "split selection", "tese");
|
||||
} else if (isWindows) {
|
||||
checkSelection(document, "split selection", "tets");
|
||||
}
|
||||
|
||||
// Trying to select where there's no text, should fail but not throw
|
||||
let result = dwu.selectAtPoint(rect.left - 20, rect.top - 20, Ci.nsIDOMWindowUtils.SELECT_CHARACTER, false);
|
||||
ok(result == false, "couldn't select?");
|
||||
|
||||
// Second div in the main page
|
||||
|
||||
let div = document.getElementById("div2");
|
||||
let rect = div.getBoundingClientRect();
|
||||
|
||||
// Centered on the first line, first character in the paragraph div
|
||||
let targetPoint = { xPos: rect.left + (charDims.width / 2),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setSingle(dwu, targetPoint.xPos + 50, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH);
|
||||
checkSelection(document, "SELECT_PARAGRAPH", "Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos.");
|
||||
|
||||
//
|
||||
// Inner IFRAME selection tests
|
||||
//
|
||||
|
||||
let frame = document.getElementById("frame1");
|
||||
let dwuFrame = frame.contentDocument
|
||||
.defaultView
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
frame.contentWindow.scrollTo(0, 0);
|
||||
|
||||
let rect = frame.getBoundingClientRect();
|
||||
|
||||
let targetPoint = { xPos: rect.left + (charDims.width / 2),
|
||||
yPos: rect.top + (charDims.height / 2) };
|
||||
setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORDNOSPACE);
|
||||
checkSelection(frame.contentWindow.document, "SELECT_WORDNOSPACE", "ttestselection2");
|
||||
setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_WORD);
|
||||
if (isLinux || isMac) {
|
||||
checkSelection(frame.contentWindow.document, "SELECT_WORD", "ttestselection2");
|
||||
} else if (isWindows) {
|
||||
checkSelection(frame.contentWindow.document, "SELECT_WORD", "ttestselection2 ");
|
||||
}
|
||||
setSingle(dwuFrame, targetPoint.xPos, targetPoint.yPos, Ci.nsIDOMWindowUtils.SELECT_PARAGRAPH);
|
||||
checkSelection(frame.contentWindow.document, "SELECT_PARAGRAPH", "ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.");
|
||||
|
||||
// Outside the frame should throw. This is a failure in coordinate setup of
|
||||
// nsDOMWindowUtils::SelectAtPoint.
|
||||
let thr = false;
|
||||
try {
|
||||
dwuFrame.selectAtPoint(rect.right + 50, rect.top, Ci.nsIDOMWindowUtils.SELECT_WORD, false);
|
||||
} catch (ex) { thr = true; }
|
||||
ok(thr == true, "selectAtPoint expected throw?");
|
||||
|
||||
done();
|
||||
}
|
||||
|
||||
let frameLoad = false;
|
||||
let pageLoad = false;
|
||||
let painted = false;
|
||||
function testReady() {
|
||||
if (frameLoad && pageLoad && painted)
|
||||
doTest();
|
||||
}
|
||||
|
||||
function onFrameLoad() {
|
||||
frameLoad = true;
|
||||
testReady();
|
||||
}
|
||||
|
||||
function onPageLoad() {
|
||||
pageLoad = true;
|
||||
testReady();
|
||||
}
|
||||
|
||||
function onPaint() {
|
||||
window.removeEventListener("MozAfterPaint", onPaint, false);
|
||||
painted = true;
|
||||
testReady();
|
||||
}
|
||||
|
||||
window.addEventListener("MozAfterPaint", onPaint, false);
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
font-family: monospace;
|
||||
margin-left: 40px;
|
||||
margin-top: 40px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#div1 {
|
||||
border: 1px solid red;
|
||||
width: 400px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
#frame1 {
|
||||
display: block;
|
||||
height: 100px;
|
||||
width: 300px;
|
||||
border: 1px solid blue;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#div2 {
|
||||
border: 1px solid green;
|
||||
}
|
||||
|
||||
#measure {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body id="body" onload="onPageLoad();">
|
||||
|
||||
<div id="div1">ttestselection1 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos. Ei munere officiis assentior pro, nibh decore ius at.</div>
|
||||
|
||||
<br />
|
||||
|
||||
<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
|
||||
|
||||
<br/>
|
||||
|
||||
<div id="div2">Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut. Ne labore incorrupte vix. Cu copiosae postulant tincidunt ius, in illud appetere contentiones eos.</div>
|
||||
|
||||
<br />
|
||||
|
||||
<span id="measure">t</span>
|
||||
|
||||
</body>
|
||||
</html>
|
21
dom/tests/mochitest/chrome/test_selectAtPoint.html
Normal file
21
dom/tests/mochitest/chrome/test_selectAtPoint.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>nsIDOMWindowUtils::selectAtPoint test</title>
|
||||
<script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
<script type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function done() {
|
||||
testwindow.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
var testwindow = window.open("selectAtPoint.html", '_new', 'width=800,height=800');
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1042,10 +1042,22 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
return GetEventCoordinatesRelativeTo(widget, aPoint, aFrame);
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
|
||||
const nsIntPoint aPoint,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
if (!aFrame || !aWidget) {
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
}
|
||||
|
||||
nsIView* view = aFrame->GetView();
|
||||
if (view) {
|
||||
nsIWidget* frameWidget = view->GetWidget();
|
||||
if (frameWidget && frameWidget == GUIEvent->widget) {
|
||||
if (frameWidget && frameWidget == aWidget) {
|
||||
// Special case this cause it happens a lot.
|
||||
// This also fixes bug 664707, events in the extra-special case of select
|
||||
// dropdown popups that are transformed.
|
||||
@ -1076,7 +1088,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent,
|
||||
}
|
||||
|
||||
nsPoint widgetToView = TranslateWidgetToView(rootFrame->PresContext(),
|
||||
widget, aPoint, rootView);
|
||||
aWidget, aPoint, rootView);
|
||||
|
||||
if (widgetToView == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
|
||||
return nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
|
||||
|
@ -416,6 +416,20 @@ public:
|
||||
const nsIntPoint aPoint,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the coordinates of a given point relative to a widget and a
|
||||
* given frame.
|
||||
* @param aWidget the event src widget
|
||||
* @param aPoint the point to get the coordinates relative to
|
||||
* @param aFrame the frame to make coordinates relative to
|
||||
* @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
|
||||
* for some reason the coordinates for the mouse are not known (e.g.,
|
||||
* the event is not a GUI event).
|
||||
*/
|
||||
static nsPoint GetEventCoordinatesRelativeTo(nsIWidget* aWidget,
|
||||
const nsIntPoint aPoint,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Get the popup frame of a given native mouse event.
|
||||
* @param aPresContext only check popups within aPresContext or a descendant
|
||||
|
@ -2780,22 +2780,70 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* SelectByTypeAtPoint
|
||||
*
|
||||
* Search for selectable content at point and attempt to select
|
||||
* based on the start and end selection behaviours.
|
||||
*
|
||||
* @param aPresContext Presentation context
|
||||
* @param aPoint Point at which selection will occur. Coordinates
|
||||
* should be relaitve to this frame.
|
||||
* @param aBeginAmountType, aEndAmountType Selection behavior, see
|
||||
* nsIFrame for definitions.
|
||||
* @param aSelectFlags Selection flags defined in nsFame.h.
|
||||
* @return success or failure at finding suitable content to select.
|
||||
*/
|
||||
nsresult
|
||||
nsFrame::SelectByTypeAtPoint(nsPresContext* aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsSelectionAmount aBeginAmountType,
|
||||
nsSelectionAmount aEndAmountType,
|
||||
uint32_t aSelectFlags)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPresContext);
|
||||
|
||||
// No point in selecting if selection is turned off
|
||||
if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF)
|
||||
return NS_OK;
|
||||
|
||||
ContentOffsets offsets = GetContentOffsetsFromPoint(aPoint, SKIP_HIDDEN);
|
||||
if (!offsets.content)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsIFrame* theFrame;
|
||||
int32_t offset;
|
||||
const nsFrameSelection* frameSelection =
|
||||
PresContext()->GetPresShell()->ConstFrameSelection();
|
||||
theFrame = frameSelection->
|
||||
GetFrameForNodeOffset(offsets.content, offsets.offset,
|
||||
nsFrameSelection::HINT(offsets.associateWithNext),
|
||||
&offset);
|
||||
if (!theFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsFrame* frame = static_cast<nsFrame*>(theFrame);
|
||||
return frame->PeekBackwardAndForward(aBeginAmountType, aEndAmountType,
|
||||
offsets.offset, aPresContext,
|
||||
aBeginAmountType != eSelectWord,
|
||||
aSelectFlags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple Mouse Press -- line or paragraph selection -- for the frame.
|
||||
* Wouldn't it be nice if this didn't have to be hardwired into Frame code?
|
||||
*/
|
||||
NS_IMETHODIMP
|
||||
nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
|
||||
nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
|
||||
nsGUIEvent* aEvent,
|
||||
nsEventStatus* aEventStatus,
|
||||
bool aControlHeld)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aEvent);
|
||||
NS_ENSURE_ARG_POINTER(aEventStatus);
|
||||
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
|
||||
if (nsEventStatus_eConsumeNoDefault == *aEventStatus ||
|
||||
DisplaySelection(aPresContext) == nsISelectionController::SELECTION_OFF) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2823,37 +2871,18 @@ nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
|
||||
ContentOffsets offsets = GetContentOffsetsFromPoint(pt, SKIP_HIDDEN);
|
||||
if (!offsets.content) return NS_ERROR_FAILURE;
|
||||
|
||||
nsIFrame* theFrame;
|
||||
int32_t offset;
|
||||
// Maybe make this a static helper?
|
||||
const nsFrameSelection* frameSelection =
|
||||
PresContext()->GetPresShell()->ConstFrameSelection();
|
||||
theFrame = frameSelection->
|
||||
GetFrameForNodeOffset(offsets.content, offsets.offset,
|
||||
nsFrameSelection::HINT(offsets.associateWithNext),
|
||||
&offset);
|
||||
if (!theFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsFrame* frame = static_cast<nsFrame*>(theFrame);
|
||||
|
||||
return frame->PeekBackwardAndForward(beginAmount, endAmount,
|
||||
offsets.offset, aPresContext,
|
||||
beginAmount != eSelectWord,
|
||||
aControlHeld);
|
||||
nsPoint relPoint = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
|
||||
return SelectByTypeAtPoint(aPresContext, relPoint, beginAmount, endAmount,
|
||||
(aControlHeld ? SELECT_ACCUMULATE : 0));
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsresult
|
||||
nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
|
||||
nsSelectionAmount aAmountForward,
|
||||
int32_t aStartPos,
|
||||
nsPresContext* aPresContext,
|
||||
bool aJumpLines,
|
||||
bool aMultipleSelection)
|
||||
uint32_t aSelectFlags)
|
||||
{
|
||||
nsIFrame* baseFrame = this;
|
||||
int32_t baseOffset = aStartPos;
|
||||
@ -2907,7 +2936,7 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
|
||||
|
||||
rv = frameSelection->HandleClick(startpos.mResultContent,
|
||||
startpos.mContentOffset, startpos.mContentOffset,
|
||||
false, aMultipleSelection,
|
||||
false, (aSelectFlags & SELECT_ACCUMULATE),
|
||||
nsFrameSelection::HINTRIGHT);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
@ -339,9 +339,7 @@ public:
|
||||
virtual bool UpdateOverflow();
|
||||
|
||||
// Selection Methods
|
||||
// XXX Doc me... (in nsIFrame.h puhleeze)
|
||||
// XXX If these are selection specific, then the name should imply selection
|
||||
// rather than generic event processing, e.g., SelectionHandlePress...
|
||||
|
||||
NS_IMETHOD HandlePress(nsPresContext* aPresContext,
|
||||
nsGUIEvent * aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
@ -359,13 +357,20 @@ public:
|
||||
nsGUIEvent * aEvent,
|
||||
nsEventStatus* aEventStatus);
|
||||
|
||||
NS_IMETHOD PeekBackwardAndForward(nsSelectionAmount aAmountBack,
|
||||
nsSelectionAmount aAmountForward,
|
||||
int32_t aStartPos,
|
||||
nsPresContext* aPresContext,
|
||||
bool aJumpLines,
|
||||
bool aMultipleSelection);
|
||||
enum { SELECT_ACCUMULATE = 0x01 };
|
||||
|
||||
nsresult PeekBackwardAndForward(nsSelectionAmount aAmountBack,
|
||||
nsSelectionAmount aAmountForward,
|
||||
int32_t aStartPos,
|
||||
nsPresContext* aPresContext,
|
||||
bool aJumpLines,
|
||||
uint32_t aSelectFlags);
|
||||
|
||||
nsresult SelectByTypeAtPoint(nsPresContext* aPresContext,
|
||||
const nsPoint& aPoint,
|
||||
nsSelectionAmount aBeginAmountType,
|
||||
nsSelectionAmount aEndAmountType,
|
||||
uint32_t aSelectFlags);
|
||||
|
||||
// Helper for GetContentAndOffsetsFromPoint; calculation of content offsets
|
||||
// in this function assumes there is no child frame that can be targeted.
|
||||
|
Loading…
Reference in New Issue
Block a user