Bug 1164693 - Part 1: Directional caret should point in caret direction in bidi paragraphs. r=smontagu

This commit is contained in:
Ted Clancy 2015-06-05 21:44:54 -04:00
parent c80a081510
commit 100cf0c0b0
6 changed files with 48 additions and 23 deletions

View File

@ -115,9 +115,14 @@ AdjustCaretFrameForLineEnd(nsIFrame** aFrame, int32_t* aOffset)
} }
static bool static bool
IsBidiUI() IsKeyboardRTL()
{ {
return Preferences::GetBool("bidi.browser.ui"); bool isKeyboardRTL = false;
nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
if (bidiKeyboard) {
bidiKeyboard->IsLangRTL(&isKeyboardRTL);
}
return isKeyboardRTL;
} }
nsCaret::nsCaret() nsCaret::nsCaret()
@ -478,6 +483,21 @@ nsCaret::SetCaretPosition(nsIDOMNode* aNode, int32_t aOffset)
SchedulePaint(); SchedulePaint();
} }
bool
nsCaret::IsBidiUI()
{
nsIFrame* frame = nullptr;
if(Selection* selection = GetSelectionInternal()) {
int32_t contentOffset;
frame = GetFrameAndOffset(selection, mOverrideContent, mOverrideOffset,
&contentOffset);
}
return (frame && frame->GetStateBits() & NS_FRAME_IS_BIDI) ||
Preferences::GetBool("bidi.browser.ui");
}
void void
nsCaret::CheckSelectionLanguageChange() nsCaret::CheckSelectionLanguageChange()
{ {
@ -485,11 +505,8 @@ nsCaret::CheckSelectionLanguageChange()
return; return;
} }
bool isKeyboardRTL = false; bool isKeyboardRTL = IsKeyboardRTL();
nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard();
if (bidiKeyboard) {
bidiKeyboard->IsLangRTL(&isKeyboardRTL);
}
// Call SelectionLanguageChange on every paint. Mostly it will be a noop // Call SelectionLanguageChange on every paint. Mostly it will be a noop
// but it should be fast anyway. This guarantees we never paint the caret // but it should be fast anyway. This guarantees we never paint the caret
// at the wrong place. // at the wrong place.
@ -678,8 +695,9 @@ nsCaret::GetCaretFrameForNodeOffset(nsFrameSelection* aFrameSelection,
if (theFrame->PresContext()->BidiEnabled()) if (theFrame->PresContext()->BidiEnabled())
{ {
// If there has been a reflow, take the caret Bidi level to be the level of the current frame // If there has been a reflow, take the caret Bidi level to be the level of the current frame
if (aBidiLevel & BIDI_LEVEL_UNDEFINED) if (aBidiLevel & BIDI_LEVEL_UNDEFINED) {
aBidiLevel = NS_GET_EMBEDDING_LEVEL(theFrame); aBidiLevel = NS_GET_EMBEDDING_LEVEL(theFrame);
}
int32_t start; int32_t start;
int32_t end; int32_t end;
@ -902,21 +920,22 @@ nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
} }
} }
// Simon -- make a hook to draw to the left or right of the caret to show keyboard language direction
aHookRect->SetEmpty(); aHookRect->SetEmpty();
if (!IsBidiUI()) {
Selection* selection = GetSelectionInternal();
if (!selection || !selection->GetFrameSelection()) {
return; return;
} }
bool isCaretRTL; if (IsBidiUI() || IsKeyboardRTL()) {
nsIBidiKeyboard* bidiKeyboard = nsContentUtils::GetBidiKeyboard(); // If caret level is RTL, draw the hook on the left; if LTR, to the right
// if bidiKeyboard->IsLangRTL() fails, there is no way to tell the
// keyboard direction, or the user has no right-to-left keyboard
// installed, so we never draw the hook.
if (bidiKeyboard && NS_SUCCEEDED(bidiKeyboard->IsLangRTL(&isCaretRTL))) {
// If keyboard language is RTL, draw the hook on the left; if LTR, to the right
// The height of the hook rectangle is the same as the width of the caret // The height of the hook rectangle is the same as the width of the caret
// rectangle. // rectangle.
int caretBidiLevel = selection->GetFrameSelection()->GetCaretBidiLevel();
if (caretBidiLevel & BIDI_LEVEL_UNDEFINED) {
caretBidiLevel = NS_GET_EMBEDDING_LEVEL(aFrame);
}
bool isCaretRTL = caretBidiLevel % 2;
if (isVertical) { if (isVertical) {
aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize, aHookRect->SetRect(aCaretRect->XMost() - bidiIndicatorSize,
aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 : aCaretRect->y + (isCaretRTL ? bidiIndicatorSize * -1 :

View File

@ -158,6 +158,7 @@ class nsCaret final : public nsISelectionListener
protected: protected:
static void CaretBlinkCallback(nsITimer *aTimer, void *aClosure); static void CaretBlinkCallback(nsITimer *aTimer, void *aClosure);
bool IsBidiUI();
void CheckSelectionLanguageChange(); void CheckSelectionLanguageChange();
void ResetBlinking(); void ResetBlinking();

View File

@ -3,13 +3,14 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head> </head>
<body onload="start()"> <body onload="start()">
<textarea onfocus="done()" style="-moz-appearance: none">س</textarea> <textarea onfocus="done()" style="-moz-appearance: none">س&lrm;</textarea>
<script> <script>
var textarea = document.querySelector("textarea"); var textarea = document.querySelector("textarea");
function start() { function start() {
textarea.focus(); textarea.focus();
} }
function done() { function done() {
textarea.selectionStart = textarea.selectionEnd = 2;
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
</script> </script>

View File

@ -1,12 +1,13 @@
<html class="reftest-wait"> <html class="reftest-wait">
<body onload="start()"> <body onload="start()">
<textarea dir="rtl" onfocus="done()" style="-moz-appearance: none">s</textarea> <textarea dir="rtl" onfocus="done()" style="-moz-appearance: none">s&rlm;</textarea>
<script> <script>
var textarea = document.querySelector("textarea"); var textarea = document.querySelector("textarea");
function start() { function start() {
textarea.focus(); textarea.focus();
} }
function done() { function done() {
textarea.selectionStart = textarea.selectionEnd = 2;
document.documentElement.removeAttribute("class"); document.documentElement.removeAttribute("class");
} }
</script> </script>

View File

@ -621,7 +621,9 @@ private:
uint32_t aContentOffset, uint32_t aContentOffset,
nsSelectionAmount aAmount, nsSelectionAmount aAmount,
CaretAssociateHint aHint); CaretAssociateHint aHint);
void BidiLevelFromClick(nsIContent *aNewFocus, uint32_t aContentOffset); void BidiLevelFromClick(nsIContent *aNewFocus,
uint32_t aContentOffset,
CaretAssociateHint aHint);
nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent *aNode, nsPrevNextBidiLevels GetPrevNextBidiLevels(nsIContent *aNode,
uint32_t aContentOffset, uint32_t aContentOffset,
CaretAssociateHint aHint, CaretAssociateHint aHint,

View File

@ -1431,12 +1431,13 @@ void nsFrameSelection::BidiLevelFromMove(nsIPresShell* aPresShell,
* @param aContentOffset is the new caret position, as an offset into aNode * @param aContentOffset is the new caret position, as an offset into aNode
*/ */
void nsFrameSelection::BidiLevelFromClick(nsIContent *aNode, void nsFrameSelection::BidiLevelFromClick(nsIContent *aNode,
uint32_t aContentOffset) uint32_t aContentOffset,
CaretAssociateHint aHint)
{ {
nsIFrame* clickInFrame=nullptr; nsIFrame* clickInFrame=nullptr;
int32_t OffsetNotUsed; int32_t OffsetNotUsed;
clickInFrame = GetFrameForNodeOffset(aNode, aContentOffset, mHint, &OffsetNotUsed); clickInFrame = GetFrameForNodeOffset(aNode, aContentOffset, aHint, &OffsetNotUsed);
if (!clickInFrame) if (!clickInFrame)
return; return;
@ -1515,7 +1516,7 @@ nsFrameSelection::HandleClick(nsIContent* aNewFocus,
// Don't take focus when dragging off of a table // Don't take focus when dragging off of a table
if (!mDragSelectingCells) if (!mDragSelectingCells)
{ {
BidiLevelFromClick(aNewFocus, aContentOffset); BidiLevelFromClick(aNewFocus, aContentOffset, aHint);
PostReason(nsISelectionListener::MOUSEDOWN_REASON + nsISelectionListener::DRAG_REASON); PostReason(nsISelectionListener::MOUSEDOWN_REASON + nsISelectionListener::DRAG_REASON);
if (aContinueSelection && if (aContinueSelection &&
AdjustForMaintainedSelection(aNewFocus, aContentOffset)) AdjustForMaintainedSelection(aNewFocus, aContentOffset))